aiobungie
A Pythonic async/await wrapper for interacting with the Bungie API.
Base client.
Example
import aiobungie
client = aiobungie.Client('YOUR_API_KEY')
# Search for Destiny2 users.
async def main() -> None:
async with client.rest:
users = await client.search_users('Crit')
# Iterate over the users and take the first 5 results.
for user in users.take(5):
print(f'{user.name} ({user.code})')
# Iterate through the users memberships.
for membership in user.memberships:
print(membership.type, membership.id)
client.run(main()) # or asyncio.run(main())
Single RESTClient instance.
The difference between base client and the REST clients:
- No Hight-Level concepts.
- All returned data are pure JSON objects from the API.
- No object creation.
Example
import aiobungie
async def main() -> None:
# Using `async with` context manager to close the session properly.
async with aiobungie.RESTClient("TOKEN") as rest:
payload = await rest.fetch_player('Fate怒', 4275)
for membership in payload:
print(membership['membershipId'], membership['iconPath'])
import asyncio
asyncio.run(main())
REST client pool.
A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.
Example
import aiobungie
import asyncio
pool = aiobungie.RESTPool("token")
async def func1() -> None:
async with pool.acquire() as instance:
tokens = await instance.fetch_oauth2_tokens('code')
pool.metadata['tokens'] = tokens
# Other instance may access the tokens from pool since its shared.
async def func2() -> None:
async with pool.acquire() as instance:
tokens = pool.metadata['tokens']
tokens = await instance.refresh_access_token(tokens.refresh_token)
async def main() -> None:
await asyncio.gather(func1(), func2())
asyncio.run(main())
Should you use the base client or the REST client? This returns to you. For an example if you're building a website.
You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.
Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
1# MIT License 2# 3# Copyright (c) 2020 - Present nxtlo 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API. 24 25Base client. 26 27Example 28------- 29```py 30import aiobungie 31 32client = aiobungie.Client('YOUR_API_KEY') 33 34# Search for Destiny2 users. 35async def main() -> None: 36 async with client.rest: 37 users = await client.search_users('Crit') 38 39 # Iterate over the users and take the first 5 results. 40 for user in users.take(5): 41 print(f'{user.name} ({user.code})') 42 43 # Iterate through the users memberships. 44 for membership in user.memberships: 45 print(membership.type, membership.id) 46 47client.run(main()) # or asyncio.run(main()) 48``` 49 50Single RESTClient instance. 51 52The difference between base client and the REST clients: 53 54* No Hight-Level concepts. 55* All returned data are pure JSON objects from the API. 56* No object creation. 57 58Example 59------- 60```py 61import aiobungie 62 63async def main() -> None: 64 # Using `async with` context manager to close the session properly. 65 async with aiobungie.RESTClient("TOKEN") as rest: 66 payload = await rest.fetch_player('Fate怒', 4275) 67 68 for membership in payload: 69 print(membership['membershipId'], membership['iconPath']) 70 71import asyncio 72asyncio.run(main()) 73``` 74 75REST client pool. 76 77A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection. 78 79Example 80------- 81```py 82import aiobungie 83import asyncio 84 85pool = aiobungie.RESTPool("token") 86 87async def func1() -> None: 88 async with pool.acquire() as instance: 89 tokens = await instance.fetch_oauth2_tokens('code') 90 pool.metadata['tokens'] = tokens 91 92# Other instance may access the tokens from pool since its shared. 93 94async def func2() -> None: 95 async with pool.acquire() as instance: 96 tokens = pool.metadata['tokens'] 97 tokens = await instance.refresh_access_token(tokens.refresh_token) 98 99async def main() -> None: 100 await asyncio.gather(func1(), func2()) 101 102asyncio.run(main()) 103``` 104 105Should you use the base client or the REST client? 106This returns to you. For an example if you're building a website. 107 108You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. 109Which gives you the freedom to deserialize it and implement your own logic in the front-end. 110 111Or of you're building a Discord bot for an example or something simple. The base client is the way to go. 112""" 113 114 115from __future__ import annotations 116 117from aiobungie import builders 118from aiobungie import crates 119from aiobungie import interfaces 120from aiobungie import traits 121from aiobungie import typedefs 122from aiobungie import url 123from aiobungie.client import Client 124from aiobungie.error import * 125from aiobungie.internal import iterators 126from aiobungie.internal.assets import Image 127from aiobungie.internal.enums import * 128from aiobungie.internal.factory import Factory 129from aiobungie.internal.iterators import * 130from aiobungie.rest import * 131from aiobungie.undefined import UNDEFINED 132from aiobungie.undefined import UndefinedOr 133from aiobungie.undefined import UndefinedType 134 135from .metadata import __about__ 136from .metadata import __author__ 137from .metadata import __docs__ 138from .metadata import __email__ 139from .metadata import __license__ 140from .metadata import __url__ 141from .metadata import __version__ 142 143# Alias for crate for backwards compatibility. 144crate = crates 145 146# Activity enums 147from .crates.activity import Difficulty 148 149# Components enums 150from .crates.components import ComponentFields 151from .crates.components import ComponentPrivacy 152 153# Entity enums 154from .crates.entity import GatingScope 155from .crates.entity import ObjectiveUIStyle 156from .crates.entity import ValueUIStyle 157 158# Fireteam enums. 159from .crates.fireteams import FireteamActivity 160from .crates.fireteams import FireteamDate 161from .crates.fireteams import FireteamLanguage 162from .crates.fireteams import FireteamPlatform 163 164# Records enums 165from .crates.records import RecordState 166 167__all__ = [mod for mod in dir() if not mod.startswith("_")] # type: ignore
74@attrs.define(auto_exc=True) 75class AiobungieError(RuntimeError): 76 """Base class that all other exceptions inherit from."""
Base class that all other exceptions inherit from.
Inherited Members
- builtins.BaseException
- with_traceback
643@typing.final 644class AmmoType(int, Enum): 645 """AN enum for Detyiny 2 ammo types.""" 646 647 NONE = 0 648 PRIMARY = 1 649 SPECIAL = 2 650 HEAVY = 3
AN enum for Detyiny 2 ammo types.
164@attrs.define(auto_exc=True) 165class BadRequest(HTTPError): 166 """An exception raised when requesting a resource with the provided data is wrong.""" 167 168 url: typing.Optional[typedefs.StrOrURL] 169 """The URL/endpoint caused this error.""" 170 171 body: typing.Any 172 """The response body.""" 173 174 headers: multidict.CIMultiDictProxy[str] 175 """The response headers.""" 176 177 http_status: http.HTTPStatus = attrs.field( 178 default=http.HTTPStatus.BAD_REQUEST, init=False 179 )
An exception raised when requesting a resource with the provided data is wrong.
2def __init__(self, message, url, body, headers): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = attr_dict['http_status'].default 8 BaseException.__init__(self, self.message,self.url,self.body,self.headers)
Method generated by attrs for class BadRequest.
698@typing.final 699class ClanMemberType(int, Enum): 700 """An enum for bungie clan member types.""" 701 702 NONE = 0 703 BEGINNER = 1 704 MEMBER = 2 705 ADMIN = 3 706 ACTING_FOUNDER = 4 707 FOUNDER = 5
An enum for bungie clan member types.
474@typing.final 475class Class(int, Enum): 476 """An Enum for Destiny character classes.""" 477 478 TITAN = 0 479 HUNTER = 1 480 WARLOCK = 2 481 UNKNOWN = 3
An Enum for Destiny character classes.
60class Client(traits.ClientApp): 61 """Standard Bungie API client application. 62 63 This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory` 64 and returns `aiobungie.crates` Python object implementations of the responses. 65 66 A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts. 67 68 Example 69 ------- 70 ```py 71 import aiobungie 72 73 client = aiobungie.Client('...') 74 75 async def main(): 76 async with client.rest: 77 user = await client.fetch_current_user_memberships('...') 78 print(user) 79 ``` 80 81 Parameters 82 ----------- 83 token: `str` 84 Your Bungie's API key or Token from the developer's portal. 85 86 Other Parameters 87 ---------------- 88 max_retries : `int` 89 The max retries number to retry if the request hit a `5xx` status code. 90 max_ratelimit_retries : `int` 91 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 92 client_secret : `str | None` 93 An optional application client secret, 94 This is only needed if you're fetching OAuth2 tokens with this client. 95 client_id : `int | None` 96 An optional application client id, 97 This is only needed if you're fetching OAuth2 tokens with this client. 98 """ 99 100 __slots__ = ("_rest", "_factory") 101 102 def __init__( 103 self, 104 token: str, 105 /, 106 client_secret: typing.Optional[str] = None, 107 client_id: typing.Optional[int] = None, 108 *, 109 max_retries: int = 4, 110 max_ratelimit_retries: int = 3, 111 ) -> None: 112 113 self._rest = rest_.RESTClient( 114 token, 115 client_secret, 116 client_id, 117 max_retries=max_retries, 118 max_ratelimit_retries=max_ratelimit_retries, 119 ) 120 121 self._factory = factory_.Factory(self) 122 123 @property 124 def factory(self) -> factory_.Factory: 125 return self._factory 126 127 @property 128 def rest(self) -> interfaces.RESTInterface: 129 return self._rest 130 131 @property 132 def request(self) -> Client: 133 return self 134 135 @property 136 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 137 return self._rest.metadata 138 139 def run( 140 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 141 ) -> None: 142 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 143 try: 144 if not loop.is_running(): 145 loop.set_debug(debug) 146 loop.run_until_complete(future) 147 148 except Exception as exc: 149 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 150 151 except KeyboardInterrupt: 152 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 153 return 154 155 # * User methods. 156 157 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 158 """Fetch and return a user object of the bungie net user associated with account. 159 160 .. warning:: 161 This method requires OAuth2 scope and a Bearer access token. 162 163 Parameters 164 ---------- 165 access_token : `str` 166 A valid Bearer access token for the authorization. 167 168 Returns 169 ------- 170 `aiobungie.crates.user.User` 171 A user object includes the Destiny memberships and Bungie.net user. 172 """ 173 resp = await self.rest.fetch_current_user_memberships(access_token) 174 175 return self.factory.deserialize_user(resp) 176 177 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 178 """Fetch a Bungie user by their BungieNet id. 179 180 .. note:: 181 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 182 for other memberships. 183 184 Parameters 185 ---------- 186 id: `int` 187 The user id. 188 189 Returns 190 ------- 191 `aiobungie.crates.user.BungieUser` 192 A Bungie user. 193 194 Raises 195 ------ 196 `aiobungie.error.NotFound` 197 The user was not found. 198 """ 199 payload = await self.rest.fetch_bungie_user(id) 200 201 return self.factory.deserialize_bungie_user(payload) 202 203 async def search_users( 204 self, name: str, / 205 ) -> iterators.Iterator[user.SearchableDestinyUser]: 206 """Search for players and return all players that matches the same name. 207 208 Parameters 209 ---------- 210 name : `buildins.str` 211 The user name. 212 213 Returns 214 ------- 215 `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]` 216 A sequence of destiny memberships. 217 """ 218 payload = await self.rest.search_users(name) 219 220 return iterators.Iterator( 221 [ 222 self.factory.deserialize_searched_user(user) 223 for user in payload["searchResults"] 224 ] 225 ) 226 227 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 228 """Fetch all available user themes. 229 230 Returns 231 ------- 232 `collections.Sequence[aiobungie.crates.user.UserThemes]` 233 A sequence of user themes. 234 """ 235 data = await self.rest.fetch_user_themes() 236 237 return self.factory.deserialize_user_themes(data) 238 239 async def fetch_hard_types( 240 self, 241 credential: int, 242 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 243 /, 244 ) -> user.HardLinkedMembership: 245 """Gets any hard linked membership given a credential. 246 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 247 Cross Save aware. 248 249 Parameters 250 ---------- 251 credential: `int` 252 A valid SteamID64 253 type: `aiobungie.CredentialType` 254 The credential type. This must not be changed 255 Since its only credential that works "currently" 256 257 Returns 258 ------- 259 `aiobungie.crates.user.HardLinkedMembership` 260 Information about the hard linked data. 261 """ 262 263 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 264 265 return user.HardLinkedMembership( 266 id=int(payload["membershipId"]), 267 type=enums.MembershipType(payload["membershipType"]), 268 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 269 ) 270 271 async def fetch_membership_from_id( 272 self, 273 id: int, 274 /, 275 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 276 ) -> user.User: 277 """Fetch Bungie user's memberships from their id. 278 279 Notes 280 ----- 281 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 282 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 283 see `aiobungie.crates.user.DestinyMembership` for more details. 284 * If you only want the bungie user. Consider using `Client.fetch_user` method. 285 286 Parameters 287 ---------- 288 id : `int` 289 The user's id. 290 type : `aiobungie.MembershipType` 291 The user's membership type. 292 293 Returns 294 ------- 295 `aiobungie.crates.User` 296 A Bungie user with their membership types. 297 298 Raises 299 ------ 300 aiobungie.NotFound 301 The requested user was not found. 302 """ 303 payload = await self.rest.fetch_membership_from_id(id, type) 304 305 return self.factory.deserialize_user(payload) 306 307 async def fetch_user_credentials( 308 self, access_token: str, membership_id: int, / 309 ) -> collections.Sequence[user.UserCredentials]: 310 """Fetch an array of credential types attached to the requested account. 311 312 .. note:: 313 This method require OAuth2 Bearer access token. 314 315 Parameters 316 ---------- 317 access_token : `str` 318 The bearer access token associated with the bungie account. 319 membership_id : `int` 320 The id of the membership to return. 321 322 Returns 323 ------- 324 `collections.Sequence[aiobungie.crates.UserCredentials]` 325 A sequence of the attached user credentials. 326 327 Raises 328 ------ 329 `aiobungie.Unauthorized` 330 The access token was wrong or no access token passed. 331 """ 332 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 333 334 return self.factory.deserialize_user_credentials(resp) 335 336 # * Destiny 2. 337 338 async def fetch_profile( 339 self, 340 member_id: int, 341 type: typedefs.IntAnd[enums.MembershipType], 342 components: list[enums.ComponentType], 343 auth: typing.Optional[str] = None, 344 ) -> components.Component: 345 """ 346 Fetch a bungie profile passing components to the request. 347 348 Parameters 349 ---------- 350 member_id: `int` 351 The member's id. 352 type: `aiobungie.MembershipType` 353 A valid membership type. 354 components : `list[aiobungie.ComponentType]` 355 List of profile components to collect and return. 356 357 Other Parameters 358 ---------------- 359 auth : `typing.Optional[str]` 360 A Bearer access_token to make the request with. 361 This is optional and limited to components that only requires an Authorization token. 362 363 Returns 364 -------- 365 `aiobungie.crates.Component` 366 A Destiny 2 player profile with its components. 367 Only passed components will be available if they exists. Otherwise they will be `None` 368 369 Raises 370 ------ 371 `aiobungie.MembershipTypeError` 372 The provided membership type was invalid. 373 """ 374 data = await self.rest.fetch_profile(member_id, type, components, auth) 375 return self.factory.deserialize_components(data) 376 377 async def fetch_linked_profiles( 378 self, 379 member_id: int, 380 member_type: typedefs.IntAnd[enums.MembershipType], 381 /, 382 *, 383 all: bool = False, 384 ) -> profile.LinkedProfile: 385 """Returns a summary information about all profiles linked to the requested member. 386 387 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 388 389 .. note:: 390 It will only return linked accounts whose linkages you are allowed to view. 391 392 Parameters 393 ---------- 394 member_id : `int` 395 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 396 member_type : `aiobungie.MembershipType` 397 The type for the membership whose linked Destiny account you want to return. 398 399 Other Parameters 400 ---------------- 401 all : `bool` 402 If provided and set to `True`, All memberships regardless 403 of whether they're obscured by overrides will be returned, 404 405 If provided and set to `False`, Only available memberships will be returned. 406 The default for this is `False`. 407 408 Returns 409 ------- 410 `aiobungie.crates.profile.LinkedProfile` 411 A linked profile object. 412 """ 413 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 414 415 return self.factory.deserialize_linked_profiles(resp) 416 417 async def fetch_player( 418 self, 419 name: str, 420 code: int, 421 /, 422 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 423 ) -> collections.Sequence[user.DestinyMembership]: 424 """Fetch a Destiny 2 player's memberships. 425 426 Parameters 427 ----------- 428 name: `str` 429 The unique Bungie player name. 430 code : `int` 431 The unique Bungie display name code. 432 type: `aiobungie.internal.enums.MembershipType` 433 The player's membership type, e,g. XBOX, STEAM, PSN 434 435 Returns 436 -------- 437 `collections.Sequence[aiobungie.crates.DestinyMembership]` 438 A sequence of the found Destiny 2 player memberships. 439 An empty sequence will be returned if no one found. 440 441 Raises 442 ------ 443 `aiobungie.MembershipTypeError` 444 The provided membership type was invalid. 445 """ 446 resp = await self.rest.fetch_player(name, code, type) 447 448 return self.factory.deserialize_destiny_memberships(resp) 449 450 async def fetch_character( 451 self, 452 member_id: int, 453 membership_type: typedefs.IntAnd[enums.MembershipType], 454 character_id: int, 455 components: list[enums.ComponentType], 456 auth: typing.Optional[str] = None, 457 ) -> components.CharacterComponent: 458 """Fetch a Destiny 2 character. 459 460 Parameters 461 ---------- 462 member_id: `int` 463 A valid bungie member id. 464 character_id: `int` 465 The Destiny character id to retrieve. 466 membership_type: `aiobungie.internal.enums.MembershipType` 467 The member's membership type. 468 components: `list[aiobungie.ComponentType]` 469 Multiple arguments of character components to collect and return. 470 471 Other Parameters 472 ---------------- 473 auth : `typing.Optional[str]` 474 A Bearer access_token to make the request with. 475 This is optional and limited to components that only requires an Authorization token. 476 477 Returns 478 ------- 479 `aiobungie.crates.CharacterComponent` 480 A Bungie character component. 481 482 `aiobungie.MembershipTypeError` 483 The provided membership type was invalid. 484 """ 485 resp = await self.rest.fetch_character( 486 member_id, membership_type, character_id, components, auth 487 ) 488 489 return self.factory.deserialize_character_component(resp) 490 491 async def fetch_unique_weapon_history( 492 self, 493 membership_id: int, 494 character_id: int, 495 membership_type: typedefs.IntAnd[enums.MembershipType], 496 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 497 """Fetch details about unique weapon usage for a character. Includes all exotics. 498 499 Parameters 500 ---------- 501 membership_id : `int` 502 The Destiny user membership id. 503 character_id : `int` 504 The character id to retrieve. 505 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 506 The Destiny user's membership type. 507 508 Returns 509 ------- 510 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 511 A sequence of the weapon's extended values. 512 """ 513 resp = await self._rest.fetch_unique_weapon_history( 514 membership_id, character_id, membership_type 515 ) 516 517 return [ 518 self._factory.deserialize_extended_weapon_values(weapon) 519 for weapon in resp["weapons"] 520 ] 521 522 # * Destiny 2 Activities. 523 524 async def fetch_activities( 525 self, 526 member_id: int, 527 character_id: int, 528 mode: typedefs.IntAnd[enums.GameMode], 529 *, 530 membership_type: typedefs.IntAnd[ 531 enums.MembershipType 532 ] = enums.MembershipType.ALL, 533 page: int = 0, 534 limit: int = 250, 535 ) -> iterators.Iterator[activity.Activity]: 536 """Fetch a Destiny 2 activity for the specified character id. 537 538 Parameters 539 ---------- 540 member_id: `int` 541 The user id that starts with `4611`. 542 character_id: `int` 543 The id of the character to retrieve the activities for. 544 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 545 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 546 547 Other Parameters 548 ---------------- 549 membership_type: `aiobungie.internal.enums.MembershipType` 550 The Member ship type, if nothing was passed than it will return all. 551 page: int 552 The page number. Default is `0` 553 limit: int 554 Limit the returned result. Default is `250`. 555 556 Returns 557 ------- 558 `aiobungie.iterators.Iterator[aiobungie.crates.Activity]` 559 An iterator of the player's activities. 560 561 Raises 562 ------ 563 `aiobungie.MembershipTypeError` 564 The provided membership type was invalid. 565 """ 566 resp = await self.rest.fetch_activities( 567 member_id, 568 character_id, 569 mode, 570 membership_type=membership_type, 571 page=page, 572 limit=limit, 573 ) 574 575 return self.factory.deserialize_activities(resp) 576 577 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 578 """Fetch a post activity details. 579 580 Parameters 581 ---------- 582 instance_id: `int` 583 The activity instance id. 584 585 Returns 586 ------- 587 `aiobungie.crates.PostActivity` 588 A post activity object. 589 """ 590 resp = await self.rest.fetch_post_activity(instance_id) 591 592 return self.factory.deserialize_post_activity(resp) 593 594 async def fetch_aggregated_activity_stats( 595 self, 596 character_id: int, 597 membership_id: int, 598 membership_type: typedefs.IntAnd[enums.MembershipType], 599 ) -> iterators.Iterator[activity.AggregatedActivity]: 600 """Fetch aggregated activity stats for a character. 601 602 Parameters 603 ---------- 604 character_id: `int` 605 The id of the character to retrieve the activities for. 606 membership_id: `int` 607 The id of the user that started with `4611`. 608 membership_type: `aiobungie.internal.enums.MembershipType` 609 The Member ship type. 610 611 Returns 612 ------- 613 `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]` 614 An iterator of the player's activities. 615 616 Raises 617 ------ 618 `aiobungie.MembershipTypeError` 619 The provided membership type was invalid. 620 """ 621 resp = await self.rest.fetch_aggregated_activity_stats( 622 character_id, membership_id, membership_type 623 ) 624 625 return self.factory.deserialize_aggregated_activities(resp) 626 627 # * Destiny 2 Clans or GroupsV2. 628 629 async def fetch_clan_from_id( 630 self, 631 id: int, 632 /, 633 access_token: typing.Optional[str] = None, 634 ) -> clans.Clan: 635 """Fetch a Bungie Clan by its id. 636 637 Parameters 638 ----------- 639 id: `int` 640 The clan id. 641 642 Returns 643 -------- 644 `aiobungie.crates.Clan` 645 An Bungie clan. 646 647 Raises 648 ------ 649 `aiobungie.NotFound` 650 The clan was not found. 651 """ 652 resp = await self.rest.fetch_clan_from_id(id, access_token) 653 654 return self.factory.deserialize_clan(resp) 655 656 async def fetch_clan( 657 self, 658 name: str, 659 /, 660 access_token: typing.Optional[str] = None, 661 *, 662 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 663 ) -> clans.Clan: 664 """Fetch a Clan by its name. 665 This method will return the first clan found with given name. 666 667 Parameters 668 ---------- 669 name: `str` 670 The clan name 671 672 Other Parameters 673 ---------------- 674 access_token : `typing.Optional[str]` 675 An optional access token to make the request with. 676 677 If the token was bound to a member of the clan, 678 This field `aiobungie.crates.Clan.current_user_membership` will be available 679 and will return the membership of the user who made this request. 680 type : `aiobungie.GroupType` 681 The group type, Default is aiobungie.GroupType.CLAN. 682 683 Returns 684 ------- 685 `aiobungie.crates.Clan` 686 A Bungie clan. 687 688 Raises 689 ------ 690 `aiobungie.NotFound` 691 The clan was not found. 692 """ 693 resp = await self.rest.fetch_clan(name, access_token, type=type) 694 695 return self.factory.deserialize_clan(resp) 696 697 async def fetch_clan_conversations( 698 self, clan_id: int, / 699 ) -> collections.Sequence[clans.ClanConversation]: 700 """Fetch the conversations/chat channels of the given clan id. 701 702 Parameters 703 ---------- 704 clan_id : `int` 705 The clan id. 706 707 Returns 708 `collections.Sequence[aiobungie.crates.ClanConversation]` 709 A sequence of the clan chat channels. 710 """ 711 resp = await self.rest.fetch_clan_conversations(clan_id) 712 713 return self.factory.deserialize_clan_conversations(resp) 714 715 async def fetch_clan_admins( 716 self, clan_id: int, / 717 ) -> iterators.Iterator[clans.ClanMember]: 718 """Fetch the clan founder and admins. 719 720 Parameters 721 ---------- 722 clan_id : `int` 723 The clan id. 724 725 Returns 726 ------- 727 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 728 An iterator over the found clan admins and founder. 729 730 Raises 731 ------ 732 `aiobungie.NotFound` 733 The requested clan was not found. 734 """ 735 resp = await self.rest.fetch_clan_admins(clan_id) 736 737 return self.factory.deserialize_clan_members(resp) 738 739 async def fetch_groups_for_member( 740 self, 741 member_id: int, 742 member_type: typedefs.IntAnd[enums.MembershipType], 743 /, 744 *, 745 filter: int = 0, 746 group_type: enums.GroupType = enums.GroupType.CLAN, 747 ) -> collections.Sequence[clans.GroupMember]: 748 """Fetch information about the groups that a given member has joined. 749 750 Parameters 751 ---------- 752 member_id : `int` 753 The member's id 754 member_type : `aiobungie.MembershipType` 755 The member's membership type. 756 757 Other Parameters 758 ---------------- 759 filter : `int` 760 Filter apply to list of joined groups. This Default to `0` 761 group_type : `aiobungie.GroupType` 762 The group's type. 763 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 764 765 Returns 766 ------- 767 `collections.Sequence[aiobungie.crates.GroupMember]` 768 A sequence of joined groups for the fetched member. 769 """ 770 resp = await self.rest.fetch_groups_for_member( 771 member_id, member_type, filter=filter, group_type=group_type 772 ) 773 774 return [ 775 self.factory.deserialize_group_member(group) for group in resp["results"] 776 ] 777 778 async def fetch_potential_groups_for_member( 779 self, 780 member_id: int, 781 member_type: typedefs.IntAnd[enums.MembershipType], 782 /, 783 *, 784 filter: int = 0, 785 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 786 ) -> collections.Sequence[clans.GroupMember]: 787 """Fetch the potential groups for a clan member. 788 789 Parameters 790 ---------- 791 member_id : `int` 792 The member's id 793 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 794 The member's membership type. 795 796 Other Parameters 797 ---------------- 798 filter : `int` 799 Filter apply to list of joined groups. This Default to `0` 800 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 801 The group's type. 802 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 803 804 Returns 805 ------- 806 `collections.Sequence[aiobungie.crates.GroupMember]` 807 A sequence of joined potential groups for the fetched member. 808 """ 809 resp = await self.rest.fetch_potential_groups_for_member( 810 member_id, member_type, filter=filter, group_type=group_type 811 ) 812 813 return [ 814 self.factory.deserialize_group_member(group) for group in resp["results"] 815 ] 816 817 async def fetch_clan_members( 818 self, 819 clan_id: int, 820 /, 821 *, 822 name: typing.Optional[str] = None, 823 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 824 ) -> iterators.Iterator[clans.ClanMember]: 825 """Fetch Bungie clan members. 826 827 Parameters 828 ---------- 829 clan_id : `int` 830 The clans id 831 832 Other Parameters 833 ---------------- 834 name : `typing.Optional[str]` 835 If provided, Only players matching this name will be returned. 836 type : `aiobungie.MembershipType` 837 An optional clan member's membership type. 838 This parameter is used to filter the returned results 839 by the provided membership, For an example XBox memberships only, 840 Otherwise will return all memberships. 841 842 Returns 843 ------- 844 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 845 An iterator over the bungie clan members. 846 847 Raises 848 ------ 849 `aiobungie.NotFound` 850 The clan was not found. 851 """ 852 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 853 854 return self.factory.deserialize_clan_members(resp) 855 856 async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]: 857 """Fetch the clan banners. 858 859 Returns 860 ------- 861 `collections.Sequence[aiobungie.crates.ClanBanner]` 862 A sequence of the clan banners. 863 """ 864 resp = await self.rest.fetch_clan_banners() 865 866 return self.factory.deserialize_clan_banners(resp) 867 868 # This method is required to be here since it deserialize the clan. 869 async def kick_clan_member( 870 self, 871 access_token: str, 872 /, 873 group_id: int, 874 membership_id: int, 875 membership_type: typedefs.IntAnd[enums.MembershipType], 876 ) -> clans.Clan: 877 """Kick a member from the clan. 878 879 .. note:: 880 This request requires OAuth2: oauth2: `AdminGroups` scope. 881 882 Parameters 883 ---------- 884 access_token : `str` 885 The bearer access token associated with the bungie account. 886 group_id: `int` 887 The group id. 888 membership_id : `int` 889 The member id to kick. 890 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 891 The member's membership type. 892 893 Returns 894 ------- 895 `aiobungie.crates.clan.Clan` 896 The clan that the member was kicked from. 897 """ 898 resp = await self.rest.kick_clan_member( 899 access_token, 900 group_id=group_id, 901 membership_id=membership_id, 902 membership_type=membership_type, 903 ) 904 905 return self.factory.deserialize_clan(resp) 906 907 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 908 """Fetch a Bungie clan's weekly reward state. 909 910 Parameters 911 ---------- 912 clan_id : `int` 913 The clan's id. 914 915 Returns 916 ------- 917 `aiobungie.crates.Milestone` 918 A runtime status of the clan's milestone data. 919 """ 920 921 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 922 923 return self.factory.deserialize_milestone(resp) 924 925 # * Destiny 2 Entities aka Definitions. 926 927 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 928 """Fetch a static inventory item entity given a its hash. 929 930 Parameters 931 ---------- 932 hash: `int` 933 Inventory item's hash. 934 935 Returns 936 ------- 937 `aiobungie.crates.InventoryEntity` 938 A bungie inventory item. 939 """ 940 resp = await self.rest.fetch_inventory_item(hash) 941 942 return self.factory.deserialize_inventory_entity(resp) 943 944 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 945 """Fetch a Destiny objective entity given a its hash. 946 947 Parameters 948 ---------- 949 hash: `int` 950 objective's hash. 951 952 Returns 953 ------- 954 `aiobungie.crates.ObjectiveEntity` 955 An objective entity item. 956 """ 957 resp = await self.rest.fetch_objective_entity(hash) 958 959 return self.factory.deserialize_objective_entity(resp) 960 961 async def search_entities( 962 self, name: str, entity_type: str, *, page: int = 0 963 ) -> iterators.Iterator[entity.SearchableEntity]: 964 """Search for Destiny2 entities given a name and its type. 965 966 Parameters 967 ---------- 968 name : `str` 969 The name of the entity, i.e., Thunderlord, One thousand voices. 970 entity_type : `str` 971 The type of the entity, AKA Definition, 972 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 973 974 Other Parameters 975 ---------------- 976 page : `int` 977 An optional page to return. Default to 0. 978 979 Returns 980 ------- 981 `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]` 982 An iterator over the found results matching the provided name. 983 """ 984 resp = await self.rest.search_entities(name, entity_type, page=page) 985 986 return self.factory.deserialize_inventory_results(resp) 987 988 # Fireteams 989 990 async def fetch_fireteams( 991 self, 992 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 993 *, 994 platform: typedefs.IntAnd[ 995 fireteams.FireteamPlatform 996 ] = fireteams.FireteamPlatform.ANY, 997 language: typing.Union[ 998 fireteams.FireteamLanguage, str 999 ] = fireteams.FireteamLanguage.ALL, 1000 date_range: int = 0, 1001 page: int = 0, 1002 slots_filter: int = 0, 1003 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1004 """Fetch public Bungie fireteams with open slots. 1005 1006 Parameters 1007 ---------- 1008 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1009 The fireteam activity type. 1010 1011 Other Parameters 1012 ---------------- 1013 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1014 If this is provided. Then the results will be filtered with the given platform. 1015 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1016 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1017 A locale language to filter the used language in that fireteam. 1018 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1019 date_range : `int` 1020 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1021 page : `int` 1022 The page number. By default its `0` which returns all available activities. 1023 slots_filter : `int` 1024 Filter the returned fireteams based on available slots. Default is `0` 1025 1026 Returns 1027 ------- 1028 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1029 A sequence of `aiobungie.crates.Fireteam` or `None`. 1030 """ 1031 1032 resp = await self.rest.fetch_fireteams( 1033 activity_type, 1034 platform=platform, 1035 language=language, 1036 date_range=date_range, 1037 page=page, 1038 slots_filter=slots_filter, 1039 ) 1040 1041 return self.factory.deserialize_fireteams(resp) 1042 1043 async def fetch_avaliable_clan_fireteams( 1044 self, 1045 access_token: str, 1046 group_id: int, 1047 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1048 *, 1049 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1050 language: typing.Union[fireteams.FireteamLanguage, str], 1051 date_range: int = 0, 1052 page: int = 0, 1053 public_only: bool = False, 1054 slots_filter: int = 0, 1055 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1056 """Fetch a clan's fireteams with open slots. 1057 1058 .. note:: 1059 This method requires OAuth2: ReadGroups scope. 1060 1061 Parameters 1062 ---------- 1063 access_token : `str` 1064 The bearer access token associated with the bungie account. 1065 group_id : `int` 1066 The group/clan id of the fireteam. 1067 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1068 The fireteam activity type. 1069 1070 Other Parameters 1071 ---------------- 1072 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1073 If this is provided. Then the results will be filtered with the given platform. 1074 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1075 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1076 A locale language to filter the used language in that fireteam. 1077 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1078 date_range : `int` 1079 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1080 page : `int` 1081 The page number. By default its `0` which returns all available activities. 1082 public_only: `bool` 1083 If set to True, Then only public fireteams will be returned. 1084 slots_filter : `int` 1085 Filter the returned fireteams based on available slots. Default is `0` 1086 1087 Returns 1088 ------- 1089 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1090 A sequence of fireteams found in the clan. 1091 `None` will be returned if nothing was found. 1092 """ 1093 resp = await self.rest.fetch_avaliable_clan_fireteams( 1094 access_token, 1095 group_id, 1096 activity_type, 1097 platform=platform, 1098 language=language, 1099 date_range=date_range, 1100 page=page, 1101 public_only=public_only, 1102 slots_filter=slots_filter, 1103 ) 1104 1105 return self.factory.deserialize_fireteams(resp) 1106 1107 async def fetch_clan_fireteam( 1108 self, access_token: str, fireteam_id: int, group_id: int 1109 ) -> fireteams.AvailableFireteam: 1110 """Fetch a specific clan fireteam. 1111 1112 .. note:: 1113 This method requires OAuth2: ReadGroups scope. 1114 1115 Parameters 1116 ---------- 1117 access_token : `str` 1118 The bearer access token associated with the bungie account. 1119 group_id : `int` 1120 The group/clan id to fetch the fireteam from. 1121 fireteam_id : `int` 1122 The fireteam id to fetch. 1123 1124 Returns 1125 ------- 1126 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1127 A sequence of available fireteams objects if exists. else `None` will be returned. 1128 """ 1129 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1130 1131 return self.factory.deserialize_available_fireteams( 1132 resp, no_results=True 1133 ) # type: ignore[return-value] 1134 1135 async def fetch_my_clan_fireteams( 1136 self, 1137 access_token: str, 1138 group_id: int, 1139 *, 1140 include_closed: bool = True, 1141 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1142 language: typing.Union[fireteams.FireteamLanguage, str], 1143 filtered: bool = True, 1144 page: int = 0, 1145 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1146 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1147 1148 .. note:: 1149 This method requires OAuth2: ReadGroups scope. 1150 1151 Parameters 1152 ---------- 1153 access_token : str 1154 The bearer access token associated with the bungie account. 1155 group_id : int 1156 The group/clan id to fetch. 1157 1158 Other Parameters 1159 ---------------- 1160 include_closed : bool 1161 If provided and set to True, It will also return closed fireteams. 1162 If provided and set to False, It will only return public fireteams. Default is True. 1163 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1164 If this is provided. Then the results will be filtered with the given platform. 1165 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1166 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1167 A locale language to filter the used language in that fireteam. 1168 Defaults to aiobungie.crates.FireteamLanguage.ALL 1169 filtered : bool 1170 If set to True, it will filter by clan. Otherwise not. Default is True. 1171 page : int 1172 The page number. By default its 0 which returns all available activities. 1173 1174 Returns 1175 ------- 1176 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1177 A sequence of available fireteams objects if exists. else `None` will be returned. 1178 """ 1179 resp = await self.rest.fetch_my_clan_fireteams( 1180 access_token, 1181 group_id, 1182 include_closed=include_closed, 1183 platform=platform, 1184 language=language, 1185 filtered=filtered, 1186 page=page, 1187 ) 1188 1189 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value] 1190 1191 # Friends and social. 1192 1193 async def fetch_friends( 1194 self, access_token: str, / 1195 ) -> collections.Sequence[friends.Friend]: 1196 """Fetch bungie friend list. 1197 1198 .. note:: 1199 This requests OAuth2: ReadUserData scope. 1200 1201 Parameters 1202 ----------- 1203 access_token : `str` 1204 The bearer access token associated with the bungie account. 1205 1206 Returns 1207 ------- 1208 `collections.Sequence[aiobungie.crates.Friend]` 1209 A sequence of the friends associated with that access token. 1210 """ 1211 1212 resp = await self.rest.fetch_friends(access_token) 1213 1214 return self.factory.deserialize_friends(resp) 1215 1216 async def fetch_friend_requests( 1217 self, access_token: str, / 1218 ) -> friends.FriendRequestView: 1219 """Fetch pending bungie friend requests queue. 1220 1221 .. note:: 1222 This requests OAuth2: ReadUserData scope. 1223 1224 Parameters 1225 ----------- 1226 access_token : `str` 1227 The bearer access token associated with the bungie account. 1228 1229 Returns 1230 ------- 1231 `aiobungie.crates.FriendRequestView` 1232 A friend requests view of that associated access token. 1233 """ 1234 1235 resp = await self.rest.fetch_friend_requests(access_token) 1236 1237 return self.factory.deserialize_friend_requests(resp) 1238 1239 # Applications and Developer portal. 1240 1241 async def fetch_application(self, appid: int, /) -> application.Application: 1242 """Fetch a Bungie application. 1243 1244 Parameters 1245 ----------- 1246 appid: `int` 1247 The application id. 1248 1249 Returns 1250 -------- 1251 `aiobungie.crates.Application` 1252 A Bungie application. 1253 """ 1254 resp = await self.rest.fetch_application(appid) 1255 1256 return self.factory.deserialize_app(resp) 1257 1258 # Milestones 1259 1260 async def fetch_public_milestone_content( 1261 self, milestone_hash: int, / 1262 ) -> milestones.MilestoneContent: 1263 """Fetch the milestone content given its hash. 1264 1265 Parameters 1266 ---------- 1267 milestone_hash : `int` 1268 The milestone hash. 1269 1270 Returns 1271 ------- 1272 `aiobungie.crates.milestones.MilestoneContent` 1273 A milestone content object. 1274 """ 1275 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1276 1277 return self.factory.deserialize_public_milestone_content(resp)
Standard Bungie API client application.
This client deserialize the REST JSON responses using aiobungie.Factory
and returns aiobungie.crates Python object implementations of the responses.
A aiobungie.RESTClient REST client can also be used alone for low-level concepts.
Example
import aiobungie
client = aiobungie.Client('...')
async def main():
async with client.rest:
user = await client.fetch_current_user_memberships('...')
print(user)
Parameters
- token (
str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
102 def __init__( 103 self, 104 token: str, 105 /, 106 client_secret: typing.Optional[str] = None, 107 client_id: typing.Optional[int] = None, 108 *, 109 max_retries: int = 4, 110 max_ratelimit_retries: int = 3, 111 ) -> None: 112 113 self._rest = rest_.RESTClient( 114 token, 115 client_secret, 116 client_id, 117 max_retries=max_retries, 118 max_ratelimit_retries=max_ratelimit_retries, 119 ) 120 121 self._factory = factory_.Factory(self)
A mutable mapping storage for the user's needs.
139 def run( 140 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 141 ) -> None: 142 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 143 try: 144 if not loop.is_running(): 145 loop.set_debug(debug) 146 loop.run_until_complete(future) 147 148 except Exception as exc: 149 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 150 151 except KeyboardInterrupt: 152 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 153 return
Runs a coroutine function until its complete.
This is equivalent to asyncio.get_event_loop().run_until_complete(...)
Parameters
- future (
collections.Coroutine[None, None, None]): A coroutine object. - debug (
bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
await fetch(...)
# Run the coroutine.
client.run(main())
157 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 158 """Fetch and return a user object of the bungie net user associated with account. 159 160 .. warning:: 161 This method requires OAuth2 scope and a Bearer access token. 162 163 Parameters 164 ---------- 165 access_token : `str` 166 A valid Bearer access token for the authorization. 167 168 Returns 169 ------- 170 `aiobungie.crates.user.User` 171 A user object includes the Destiny memberships and Bungie.net user. 172 """ 173 resp = await self.rest.fetch_current_user_memberships(access_token) 174 175 return self.factory.deserialize_user(resp)
Fetch and return a user object of the bungie net user associated with account.
This method requires OAuth2 scope and a Bearer access token.
Parameters
- access_token (
str): A valid Bearer access token for the authorization.
Returns
aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
177 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 178 """Fetch a Bungie user by their BungieNet id. 179 180 .. note:: 181 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 182 for other memberships. 183 184 Parameters 185 ---------- 186 id: `int` 187 The user id. 188 189 Returns 190 ------- 191 `aiobungie.crates.user.BungieUser` 192 A Bungie user. 193 194 Raises 195 ------ 196 `aiobungie.error.NotFound` 197 The user was not found. 198 """ 199 payload = await self.rest.fetch_bungie_user(id) 200 201 return self.factory.deserialize_bungie_user(payload)
Fetch a Bungie user by their BungieNet id.
This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id
for other memberships.
Parameters
- id (
int): The user id.
Returns
aiobungie.crates.user.BungieUser: A Bungie user.
Raises
aiobungie.NotFound: The user was not found.
203 async def search_users( 204 self, name: str, / 205 ) -> iterators.Iterator[user.SearchableDestinyUser]: 206 """Search for players and return all players that matches the same name. 207 208 Parameters 209 ---------- 210 name : `buildins.str` 211 The user name. 212 213 Returns 214 ------- 215 `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]` 216 A sequence of destiny memberships. 217 """ 218 payload = await self.rest.search_users(name) 219 220 return iterators.Iterator( 221 [ 222 self.factory.deserialize_searched_user(user) 223 for user in payload["searchResults"] 224 ] 225 )
Search for players and return all players that matches the same name.
Parameters
- name (
buildins.str): The user name.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]: A sequence of destiny memberships.
227 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 228 """Fetch all available user themes. 229 230 Returns 231 ------- 232 `collections.Sequence[aiobungie.crates.user.UserThemes]` 233 A sequence of user themes. 234 """ 235 data = await self.rest.fetch_user_themes() 236 237 return self.factory.deserialize_user_themes(data)
Fetch all available user themes.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
239 async def fetch_hard_types( 240 self, 241 credential: int, 242 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 243 /, 244 ) -> user.HardLinkedMembership: 245 """Gets any hard linked membership given a credential. 246 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 247 Cross Save aware. 248 249 Parameters 250 ---------- 251 credential: `int` 252 A valid SteamID64 253 type: `aiobungie.CredentialType` 254 The credential type. This must not be changed 255 Since its only credential that works "currently" 256 257 Returns 258 ------- 259 `aiobungie.crates.user.HardLinkedMembership` 260 Information about the hard linked data. 261 """ 262 263 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 264 265 return user.HardLinkedMembership( 266 id=int(payload["membershipId"]), 267 type=enums.MembershipType(payload["membershipType"]), 268 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 269 )
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
271 async def fetch_membership_from_id( 272 self, 273 id: int, 274 /, 275 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 276 ) -> user.User: 277 """Fetch Bungie user's memberships from their id. 278 279 Notes 280 ----- 281 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 282 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 283 see `aiobungie.crates.user.DestinyMembership` for more details. 284 * If you only want the bungie user. Consider using `Client.fetch_user` method. 285 286 Parameters 287 ---------- 288 id : `int` 289 The user's id. 290 type : `aiobungie.MembershipType` 291 The user's membership type. 292 293 Returns 294 ------- 295 `aiobungie.crates.User` 296 A Bungie user with their membership types. 297 298 Raises 299 ------ 300 aiobungie.NotFound 301 The requested user was not found. 302 """ 303 payload = await self.rest.fetch_membership_from_id(id, type) 304 305 return self.factory.deserialize_user(payload)
Fetch Bungie user's memberships from their id.
Notes
- This returns both BungieNet membership and a sequence of the player's DestinyMemberships
Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
see
aiobungie.crates.user.DestinyMembershipfor more details. - If you only want the bungie user. Consider using
Client.fetch_usermethod.
Parameters
- id (
int): The user's id. - type (
aiobungie.MembershipType): The user's membership type.
Returns
aiobungie.crates.User: A Bungie user with their membership types.
Raises
- aiobungie.NotFound: The requested user was not found.
307 async def fetch_user_credentials( 308 self, access_token: str, membership_id: int, / 309 ) -> collections.Sequence[user.UserCredentials]: 310 """Fetch an array of credential types attached to the requested account. 311 312 .. note:: 313 This method require OAuth2 Bearer access token. 314 315 Parameters 316 ---------- 317 access_token : `str` 318 The bearer access token associated with the bungie account. 319 membership_id : `int` 320 The id of the membership to return. 321 322 Returns 323 ------- 324 `collections.Sequence[aiobungie.crates.UserCredentials]` 325 A sequence of the attached user credentials. 326 327 Raises 328 ------ 329 `aiobungie.Unauthorized` 330 The access token was wrong or no access token passed. 331 """ 332 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 333 334 return self.factory.deserialize_user_credentials(resp)
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of the attached user credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
338 async def fetch_profile( 339 self, 340 member_id: int, 341 type: typedefs.IntAnd[enums.MembershipType], 342 components: list[enums.ComponentType], 343 auth: typing.Optional[str] = None, 344 ) -> components.Component: 345 """ 346 Fetch a bungie profile passing components to the request. 347 348 Parameters 349 ---------- 350 member_id: `int` 351 The member's id. 352 type: `aiobungie.MembershipType` 353 A valid membership type. 354 components : `list[aiobungie.ComponentType]` 355 List of profile components to collect and return. 356 357 Other Parameters 358 ---------------- 359 auth : `typing.Optional[str]` 360 A Bearer access_token to make the request with. 361 This is optional and limited to components that only requires an Authorization token. 362 363 Returns 364 -------- 365 `aiobungie.crates.Component` 366 A Destiny 2 player profile with its components. 367 Only passed components will be available if they exists. Otherwise they will be `None` 368 369 Raises 370 ------ 371 `aiobungie.MembershipTypeError` 372 The provided membership type was invalid. 373 """ 374 data = await self.rest.fetch_profile(member_id, type, components, auth) 375 return self.factory.deserialize_components(data)
Fetch a bungie profile passing components to the request.
Parameters
- member_id (
int): The member's id. - type (
aiobungie.MembershipType): A valid membership type. - components (
list[aiobungie.ComponentType]): List of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will beNone
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
377 async def fetch_linked_profiles( 378 self, 379 member_id: int, 380 member_type: typedefs.IntAnd[enums.MembershipType], 381 /, 382 *, 383 all: bool = False, 384 ) -> profile.LinkedProfile: 385 """Returns a summary information about all profiles linked to the requested member. 386 387 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 388 389 .. note:: 390 It will only return linked accounts whose linkages you are allowed to view. 391 392 Parameters 393 ---------- 394 member_id : `int` 395 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 396 member_type : `aiobungie.MembershipType` 397 The type for the membership whose linked Destiny account you want to return. 398 399 Other Parameters 400 ---------------- 401 all : `bool` 402 If provided and set to `True`, All memberships regardless 403 of whether they're obscured by overrides will be returned, 404 405 If provided and set to `False`, Only available memberships will be returned. 406 The default for this is `False`. 407 408 Returns 409 ------- 410 `aiobungie.crates.profile.LinkedProfile` 411 A linked profile object. 412 """ 413 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 414 415 return self.factory.deserialize_linked_profiles(resp)
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.crates.profile.LinkedProfile: A linked profile object.
417 async def fetch_player( 418 self, 419 name: str, 420 code: int, 421 /, 422 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 423 ) -> collections.Sequence[user.DestinyMembership]: 424 """Fetch a Destiny 2 player's memberships. 425 426 Parameters 427 ----------- 428 name: `str` 429 The unique Bungie player name. 430 code : `int` 431 The unique Bungie display name code. 432 type: `aiobungie.internal.enums.MembershipType` 433 The player's membership type, e,g. XBOX, STEAM, PSN 434 435 Returns 436 -------- 437 `collections.Sequence[aiobungie.crates.DestinyMembership]` 438 A sequence of the found Destiny 2 player memberships. 439 An empty sequence will be returned if no one found. 440 441 Raises 442 ------ 443 `aiobungie.MembershipTypeError` 444 The provided membership type was invalid. 445 """ 446 resp = await self.rest.fetch_player(name, code, type) 447 448 return self.factory.deserialize_destiny_memberships(resp)
Fetch a Destiny 2 player's memberships.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
collections.Sequence[aiobungie.crates.DestinyMembership]: A sequence of the found Destiny 2 player memberships. An empty sequence will be returned if no one found.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
450 async def fetch_character( 451 self, 452 member_id: int, 453 membership_type: typedefs.IntAnd[enums.MembershipType], 454 character_id: int, 455 components: list[enums.ComponentType], 456 auth: typing.Optional[str] = None, 457 ) -> components.CharacterComponent: 458 """Fetch a Destiny 2 character. 459 460 Parameters 461 ---------- 462 member_id: `int` 463 A valid bungie member id. 464 character_id: `int` 465 The Destiny character id to retrieve. 466 membership_type: `aiobungie.internal.enums.MembershipType` 467 The member's membership type. 468 components: `list[aiobungie.ComponentType]` 469 Multiple arguments of character components to collect and return. 470 471 Other Parameters 472 ---------------- 473 auth : `typing.Optional[str]` 474 A Bearer access_token to make the request with. 475 This is optional and limited to components that only requires an Authorization token. 476 477 Returns 478 ------- 479 `aiobungie.crates.CharacterComponent` 480 A Bungie character component. 481 482 `aiobungie.MembershipTypeError` 483 The provided membership type was invalid. 484 """ 485 resp = await self.rest.fetch_character( 486 member_id, membership_type, character_id, components, auth 487 ) 488 489 return self.factory.deserialize_character_component(resp)
Fetch a Destiny 2 character.
Parameters
- member_id (
int): A valid bungie member id. - character_id (
int): The Destiny character id to retrieve. - membership_type (
aiobungie.MembershipType): The member's membership type. - components (
list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.CharacterComponent: A Bungie character component.aiobungie.MembershipTypeError: The provided membership type was invalid.
491 async def fetch_unique_weapon_history( 492 self, 493 membership_id: int, 494 character_id: int, 495 membership_type: typedefs.IntAnd[enums.MembershipType], 496 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 497 """Fetch details about unique weapon usage for a character. Includes all exotics. 498 499 Parameters 500 ---------- 501 membership_id : `int` 502 The Destiny user membership id. 503 character_id : `int` 504 The character id to retrieve. 505 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 506 The Destiny user's membership type. 507 508 Returns 509 ------- 510 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 511 A sequence of the weapon's extended values. 512 """ 513 resp = await self._rest.fetch_unique_weapon_history( 514 membership_id, character_id, membership_type 515 ) 516 517 return [ 518 self._factory.deserialize_extended_weapon_values(weapon) 519 for weapon in resp["weapons"] 520 ]
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
collections.Sequence[aiobungie.crates.ExtendedWeaponValues]: A sequence of the weapon's extended values.
524 async def fetch_activities( 525 self, 526 member_id: int, 527 character_id: int, 528 mode: typedefs.IntAnd[enums.GameMode], 529 *, 530 membership_type: typedefs.IntAnd[ 531 enums.MembershipType 532 ] = enums.MembershipType.ALL, 533 page: int = 0, 534 limit: int = 250, 535 ) -> iterators.Iterator[activity.Activity]: 536 """Fetch a Destiny 2 activity for the specified character id. 537 538 Parameters 539 ---------- 540 member_id: `int` 541 The user id that starts with `4611`. 542 character_id: `int` 543 The id of the character to retrieve the activities for. 544 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 545 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 546 547 Other Parameters 548 ---------------- 549 membership_type: `aiobungie.internal.enums.MembershipType` 550 The Member ship type, if nothing was passed than it will return all. 551 page: int 552 The page number. Default is `0` 553 limit: int 554 Limit the returned result. Default is `250`. 555 556 Returns 557 ------- 558 `aiobungie.iterators.Iterator[aiobungie.crates.Activity]` 559 An iterator of the player's activities. 560 561 Raises 562 ------ 563 `aiobungie.MembershipTypeError` 564 The provided membership type was invalid. 565 """ 566 resp = await self.rest.fetch_activities( 567 member_id, 568 character_id, 569 mode, 570 membership_type=membership_type, 571 page=page, 572 limit=limit, 573 ) 574 575 return self.factory.deserialize_activities(resp)
Fetch a Destiny 2 activity for the specified character id.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve the activities for. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all. - page (int):
The page number. Default is
0 - limit (int):
Limit the returned result. Default is
250.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.Activity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
577 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 578 """Fetch a post activity details. 579 580 Parameters 581 ---------- 582 instance_id: `int` 583 The activity instance id. 584 585 Returns 586 ------- 587 `aiobungie.crates.PostActivity` 588 A post activity object. 589 """ 590 resp = await self.rest.fetch_post_activity(instance_id) 591 592 return self.factory.deserialize_post_activity(resp)
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.crates.PostActivity: A post activity object.
594 async def fetch_aggregated_activity_stats( 595 self, 596 character_id: int, 597 membership_id: int, 598 membership_type: typedefs.IntAnd[enums.MembershipType], 599 ) -> iterators.Iterator[activity.AggregatedActivity]: 600 """Fetch aggregated activity stats for a character. 601 602 Parameters 603 ---------- 604 character_id: `int` 605 The id of the character to retrieve the activities for. 606 membership_id: `int` 607 The id of the user that started with `4611`. 608 membership_type: `aiobungie.internal.enums.MembershipType` 609 The Member ship type. 610 611 Returns 612 ------- 613 `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]` 614 An iterator of the player's activities. 615 616 Raises 617 ------ 618 `aiobungie.MembershipTypeError` 619 The provided membership type was invalid. 620 """ 621 resp = await self.rest.fetch_aggregated_activity_stats( 622 character_id, membership_id, membership_type 623 ) 624 625 return self.factory.deserialize_aggregated_activities(resp)
Fetch aggregated activity stats for a character.
Parameters
- character_id (
int): The id of the character to retrieve the activities for. - membership_id (
int): The id of the user that started with4611. - membership_type (
aiobungie.MembershipType): The Member ship type.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
629 async def fetch_clan_from_id( 630 self, 631 id: int, 632 /, 633 access_token: typing.Optional[str] = None, 634 ) -> clans.Clan: 635 """Fetch a Bungie Clan by its id. 636 637 Parameters 638 ----------- 639 id: `int` 640 The clan id. 641 642 Returns 643 -------- 644 `aiobungie.crates.Clan` 645 An Bungie clan. 646 647 Raises 648 ------ 649 `aiobungie.NotFound` 650 The clan was not found. 651 """ 652 resp = await self.rest.fetch_clan_from_id(id, access_token) 653 654 return self.factory.deserialize_clan(resp)
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Returns
aiobungie.crates.Clan: An Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
656 async def fetch_clan( 657 self, 658 name: str, 659 /, 660 access_token: typing.Optional[str] = None, 661 *, 662 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 663 ) -> clans.Clan: 664 """Fetch a Clan by its name. 665 This method will return the first clan found with given name. 666 667 Parameters 668 ---------- 669 name: `str` 670 The clan name 671 672 Other Parameters 673 ---------------- 674 access_token : `typing.Optional[str]` 675 An optional access token to make the request with. 676 677 If the token was bound to a member of the clan, 678 This field `aiobungie.crates.Clan.current_user_membership` will be available 679 and will return the membership of the user who made this request. 680 type : `aiobungie.GroupType` 681 The group type, Default is aiobungie.GroupType.CLAN. 682 683 Returns 684 ------- 685 `aiobungie.crates.Clan` 686 A Bungie clan. 687 688 Raises 689 ------ 690 `aiobungie.NotFound` 691 The clan was not found. 692 """ 693 resp = await self.rest.fetch_clan(name, access_token, type=type) 694 695 return self.factory.deserialize_clan(resp)
Fetch a Clan by its name. This method will return the first clan found with given name.
Parameters
- name (
str): The clan name
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.GroupType): The group type, Default is aiobungie.GroupType.CLAN.
Returns
aiobungie.crates.Clan: A Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
697 async def fetch_clan_conversations( 698 self, clan_id: int, / 699 ) -> collections.Sequence[clans.ClanConversation]: 700 """Fetch the conversations/chat channels of the given clan id. 701 702 Parameters 703 ---------- 704 clan_id : `int` 705 The clan id. 706 707 Returns 708 `collections.Sequence[aiobungie.crates.ClanConversation]` 709 A sequence of the clan chat channels. 710 """ 711 resp = await self.rest.fetch_clan_conversations(clan_id) 712 713 return self.factory.deserialize_clan_conversations(resp)
Fetch the conversations/chat channels of the given clan id.
Parameters
- clan_id (
int): The clan id. - Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of the clan chat channels.
715 async def fetch_clan_admins( 716 self, clan_id: int, / 717 ) -> iterators.Iterator[clans.ClanMember]: 718 """Fetch the clan founder and admins. 719 720 Parameters 721 ---------- 722 clan_id : `int` 723 The clan id. 724 725 Returns 726 ------- 727 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 728 An iterator over the found clan admins and founder. 729 730 Raises 731 ------ 732 `aiobungie.NotFound` 733 The requested clan was not found. 734 """ 735 resp = await self.rest.fetch_clan_admins(clan_id) 736 737 return self.factory.deserialize_clan_members(resp)
Fetch the clan founder and admins.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]: An iterator over the found clan admins and founder.
Raises
aiobungie.NotFound: The requested clan was not found.
739 async def fetch_groups_for_member( 740 self, 741 member_id: int, 742 member_type: typedefs.IntAnd[enums.MembershipType], 743 /, 744 *, 745 filter: int = 0, 746 group_type: enums.GroupType = enums.GroupType.CLAN, 747 ) -> collections.Sequence[clans.GroupMember]: 748 """Fetch information about the groups that a given member has joined. 749 750 Parameters 751 ---------- 752 member_id : `int` 753 The member's id 754 member_type : `aiobungie.MembershipType` 755 The member's membership type. 756 757 Other Parameters 758 ---------------- 759 filter : `int` 760 Filter apply to list of joined groups. This Default to `0` 761 group_type : `aiobungie.GroupType` 762 The group's type. 763 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 764 765 Returns 766 ------- 767 `collections.Sequence[aiobungie.crates.GroupMember]` 768 A sequence of joined groups for the fetched member. 769 """ 770 resp = await self.rest.fetch_groups_for_member( 771 member_id, member_type, filter=filter, group_type=group_type 772 ) 773 774 return [ 775 self.factory.deserialize_group_member(group) for group in resp["results"] 776 ]
Fetch information about the groups that a given member has joined.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.MembershipType): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.GroupType): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined groups for the fetched member.
778 async def fetch_potential_groups_for_member( 779 self, 780 member_id: int, 781 member_type: typedefs.IntAnd[enums.MembershipType], 782 /, 783 *, 784 filter: int = 0, 785 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 786 ) -> collections.Sequence[clans.GroupMember]: 787 """Fetch the potential groups for a clan member. 788 789 Parameters 790 ---------- 791 member_id : `int` 792 The member's id 793 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 794 The member's membership type. 795 796 Other Parameters 797 ---------------- 798 filter : `int` 799 Filter apply to list of joined groups. This Default to `0` 800 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 801 The group's type. 802 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 803 804 Returns 805 ------- 806 `collections.Sequence[aiobungie.crates.GroupMember]` 807 A sequence of joined potential groups for the fetched member. 808 """ 809 resp = await self.rest.fetch_potential_groups_for_member( 810 member_id, member_type, filter=filter, group_type=group_type 811 ) 812 813 return [ 814 self.factory.deserialize_group_member(group) for group in resp["results"] 815 ]
Fetch the potential groups for a clan member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined potential groups for the fetched member.
817 async def fetch_clan_members( 818 self, 819 clan_id: int, 820 /, 821 *, 822 name: typing.Optional[str] = None, 823 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 824 ) -> iterators.Iterator[clans.ClanMember]: 825 """Fetch Bungie clan members. 826 827 Parameters 828 ---------- 829 clan_id : `int` 830 The clans id 831 832 Other Parameters 833 ---------------- 834 name : `typing.Optional[str]` 835 If provided, Only players matching this name will be returned. 836 type : `aiobungie.MembershipType` 837 An optional clan member's membership type. 838 This parameter is used to filter the returned results 839 by the provided membership, For an example XBox memberships only, 840 Otherwise will return all memberships. 841 842 Returns 843 ------- 844 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 845 An iterator over the bungie clan members. 846 847 Raises 848 ------ 849 `aiobungie.NotFound` 850 The clan was not found. 851 """ 852 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 853 854 return self.factory.deserialize_clan_members(resp)
Fetch Bungie clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]: An iterator over the bungie clan members.
Raises
aiobungie.NotFound: The clan was not found.
869 async def kick_clan_member( 870 self, 871 access_token: str, 872 /, 873 group_id: int, 874 membership_id: int, 875 membership_type: typedefs.IntAnd[enums.MembershipType], 876 ) -> clans.Clan: 877 """Kick a member from the clan. 878 879 .. note:: 880 This request requires OAuth2: oauth2: `AdminGroups` scope. 881 882 Parameters 883 ---------- 884 access_token : `str` 885 The bearer access token associated with the bungie account. 886 group_id: `int` 887 The group id. 888 membership_id : `int` 889 The member id to kick. 890 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 891 The member's membership type. 892 893 Returns 894 ------- 895 `aiobungie.crates.clan.Clan` 896 The clan that the member was kicked from. 897 """ 898 resp = await self.rest.kick_clan_member( 899 access_token, 900 group_id=group_id, 901 membership_id=membership_id, 902 membership_type=membership_type, 903 ) 904 905 return self.factory.deserialize_clan(resp)
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.crates.clan.Clan: The clan that the member was kicked from.
907 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 908 """Fetch a Bungie clan's weekly reward state. 909 910 Parameters 911 ---------- 912 clan_id : `int` 913 The clan's id. 914 915 Returns 916 ------- 917 `aiobungie.crates.Milestone` 918 A runtime status of the clan's milestone data. 919 """ 920 921 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 922 923 return self.factory.deserialize_milestone(resp)
Fetch a Bungie clan's weekly reward state.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.crates.Milestone: A runtime status of the clan's milestone data.
927 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 928 """Fetch a static inventory item entity given a its hash. 929 930 Parameters 931 ---------- 932 hash: `int` 933 Inventory item's hash. 934 935 Returns 936 ------- 937 `aiobungie.crates.InventoryEntity` 938 A bungie inventory item. 939 """ 940 resp = await self.rest.fetch_inventory_item(hash) 941 942 return self.factory.deserialize_inventory_entity(resp)
Fetch a static inventory item entity given a its hash.
Parameters
- hash (
int): Inventory item's hash.
Returns
aiobungie.crates.InventoryEntity: A bungie inventory item.
944 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 945 """Fetch a Destiny objective entity given a its hash. 946 947 Parameters 948 ---------- 949 hash: `int` 950 objective's hash. 951 952 Returns 953 ------- 954 `aiobungie.crates.ObjectiveEntity` 955 An objective entity item. 956 """ 957 resp = await self.rest.fetch_objective_entity(hash) 958 959 return self.factory.deserialize_objective_entity(resp)
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity item.
961 async def search_entities( 962 self, name: str, entity_type: str, *, page: int = 0 963 ) -> iterators.Iterator[entity.SearchableEntity]: 964 """Search for Destiny2 entities given a name and its type. 965 966 Parameters 967 ---------- 968 name : `str` 969 The name of the entity, i.e., Thunderlord, One thousand voices. 970 entity_type : `str` 971 The type of the entity, AKA Definition, 972 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 973 974 Other Parameters 975 ---------------- 976 page : `int` 977 An optional page to return. Default to 0. 978 979 Returns 980 ------- 981 `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]` 982 An iterator over the found results matching the provided name. 983 """ 984 resp = await self.rest.search_entities(name, entity_type, page=page) 985 986 return self.factory.deserialize_inventory_results(resp)
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinitionfor emblems, weapons, and other inventory items.
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]: An iterator over the found results matching the provided name.
990 async def fetch_fireteams( 991 self, 992 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 993 *, 994 platform: typedefs.IntAnd[ 995 fireteams.FireteamPlatform 996 ] = fireteams.FireteamPlatform.ANY, 997 language: typing.Union[ 998 fireteams.FireteamLanguage, str 999 ] = fireteams.FireteamLanguage.ALL, 1000 date_range: int = 0, 1001 page: int = 0, 1002 slots_filter: int = 0, 1003 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1004 """Fetch public Bungie fireteams with open slots. 1005 1006 Parameters 1007 ---------- 1008 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1009 The fireteam activity type. 1010 1011 Other Parameters 1012 ---------------- 1013 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1014 If this is provided. Then the results will be filtered with the given platform. 1015 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1016 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1017 A locale language to filter the used language in that fireteam. 1018 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1019 date_range : `int` 1020 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1021 page : `int` 1022 The page number. By default its `0` which returns all available activities. 1023 slots_filter : `int` 1024 Filter the returned fireteams based on available slots. Default is `0` 1025 1026 Returns 1027 ------- 1028 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1029 A sequence of `aiobungie.crates.Fireteam` or `None`. 1030 """ 1031 1032 resp = await self.rest.fetch_fireteams( 1033 activity_type, 1034 platform=platform, 1035 language=language, 1036 date_range=date_range, 1037 page=page, 1038 slots_filter=slots_filter, 1039 ) 1040 1041 return self.factory.deserialize_fireteams(resp)
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[fireteams.Fireteam]]: A sequence ofaiobungie.crates.FireteamorNone.
1043 async def fetch_avaliable_clan_fireteams( 1044 self, 1045 access_token: str, 1046 group_id: int, 1047 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1048 *, 1049 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1050 language: typing.Union[fireteams.FireteamLanguage, str], 1051 date_range: int = 0, 1052 page: int = 0, 1053 public_only: bool = False, 1054 slots_filter: int = 0, 1055 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1056 """Fetch a clan's fireteams with open slots. 1057 1058 .. note:: 1059 This method requires OAuth2: ReadGroups scope. 1060 1061 Parameters 1062 ---------- 1063 access_token : `str` 1064 The bearer access token associated with the bungie account. 1065 group_id : `int` 1066 The group/clan id of the fireteam. 1067 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1068 The fireteam activity type. 1069 1070 Other Parameters 1071 ---------------- 1072 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1073 If this is provided. Then the results will be filtered with the given platform. 1074 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1075 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1076 A locale language to filter the used language in that fireteam. 1077 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1078 date_range : `int` 1079 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1080 page : `int` 1081 The page number. By default its `0` which returns all available activities. 1082 public_only: `bool` 1083 If set to True, Then only public fireteams will be returned. 1084 slots_filter : `int` 1085 Filter the returned fireteams based on available slots. Default is `0` 1086 1087 Returns 1088 ------- 1089 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1090 A sequence of fireteams found in the clan. 1091 `None` will be returned if nothing was found. 1092 """ 1093 resp = await self.rest.fetch_avaliable_clan_fireteams( 1094 access_token, 1095 group_id, 1096 activity_type, 1097 platform=platform, 1098 language=language, 1099 date_range=date_range, 1100 page=page, 1101 public_only=public_only, 1102 slots_filter=slots_filter, 1103 ) 1104 1105 return self.factory.deserialize_fireteams(resp)
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults to0. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan.Nonewill be returned if nothing was found.
1107 async def fetch_clan_fireteam( 1108 self, access_token: str, fireteam_id: int, group_id: int 1109 ) -> fireteams.AvailableFireteam: 1110 """Fetch a specific clan fireteam. 1111 1112 .. note:: 1113 This method requires OAuth2: ReadGroups scope. 1114 1115 Parameters 1116 ---------- 1117 access_token : `str` 1118 The bearer access token associated with the bungie account. 1119 group_id : `int` 1120 The group/clan id to fetch the fireteam from. 1121 fireteam_id : `int` 1122 The fireteam id to fetch. 1123 1124 Returns 1125 ------- 1126 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1127 A sequence of available fireteams objects if exists. else `None` will be returned. 1128 """ 1129 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1130 1131 return self.factory.deserialize_available_fireteams( 1132 resp, no_results=True 1133 ) # type: ignore[return-value]
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
typing.Optional[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1135 async def fetch_my_clan_fireteams( 1136 self, 1137 access_token: str, 1138 group_id: int, 1139 *, 1140 include_closed: bool = True, 1141 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1142 language: typing.Union[fireteams.FireteamLanguage, str], 1143 filtered: bool = True, 1144 page: int = 0, 1145 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1146 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1147 1148 .. note:: 1149 This method requires OAuth2: ReadGroups scope. 1150 1151 Parameters 1152 ---------- 1153 access_token : str 1154 The bearer access token associated with the bungie account. 1155 group_id : int 1156 The group/clan id to fetch. 1157 1158 Other Parameters 1159 ---------------- 1160 include_closed : bool 1161 If provided and set to True, It will also return closed fireteams. 1162 If provided and set to False, It will only return public fireteams. Default is True. 1163 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1164 If this is provided. Then the results will be filtered with the given platform. 1165 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1166 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1167 A locale language to filter the used language in that fireteam. 1168 Defaults to aiobungie.crates.FireteamLanguage.ALL 1169 filtered : bool 1170 If set to True, it will filter by clan. Otherwise not. Default is True. 1171 page : int 1172 The page number. By default its 0 which returns all available activities. 1173 1174 Returns 1175 ------- 1176 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1177 A sequence of available fireteams objects if exists. else `None` will be returned. 1178 """ 1179 resp = await self.rest.fetch_my_clan_fireteams( 1180 access_token, 1181 group_id, 1182 include_closed=include_closed, 1183 platform=platform, 1184 language=language, 1185 filtered=filtered, 1186 page=page, 1187 ) 1188 1189 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value]
A method that's similar to fetch_fireteams but requires OAuth2.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (str): The bearer access token associated with the bungie account.
- group_id (int): The group/clan id to fetch.
Other Parameters
- include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
- platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
- language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
- filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
- page (int): The page number. By default its 0 which returns all available activities.
Returns
collections.Sequence[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1193 async def fetch_friends( 1194 self, access_token: str, / 1195 ) -> collections.Sequence[friends.Friend]: 1196 """Fetch bungie friend list. 1197 1198 .. note:: 1199 This requests OAuth2: ReadUserData scope. 1200 1201 Parameters 1202 ----------- 1203 access_token : `str` 1204 The bearer access token associated with the bungie account. 1205 1206 Returns 1207 ------- 1208 `collections.Sequence[aiobungie.crates.Friend]` 1209 A sequence of the friends associated with that access token. 1210 """ 1211 1212 resp = await self.rest.fetch_friends(access_token) 1213 1214 return self.factory.deserialize_friends(resp)
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of the friends associated with that access token.
1216 async def fetch_friend_requests( 1217 self, access_token: str, / 1218 ) -> friends.FriendRequestView: 1219 """Fetch pending bungie friend requests queue. 1220 1221 .. note:: 1222 This requests OAuth2: ReadUserData scope. 1223 1224 Parameters 1225 ----------- 1226 access_token : `str` 1227 The bearer access token associated with the bungie account. 1228 1229 Returns 1230 ------- 1231 `aiobungie.crates.FriendRequestView` 1232 A friend requests view of that associated access token. 1233 """ 1234 1235 resp = await self.rest.fetch_friend_requests(access_token) 1236 1237 return self.factory.deserialize_friend_requests(resp)
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.crates.FriendRequestView: A friend requests view of that associated access token.
1241 async def fetch_application(self, appid: int, /) -> application.Application: 1242 """Fetch a Bungie application. 1243 1244 Parameters 1245 ----------- 1246 appid: `int` 1247 The application id. 1248 1249 Returns 1250 -------- 1251 `aiobungie.crates.Application` 1252 A Bungie application. 1253 """ 1254 resp = await self.rest.fetch_application(appid) 1255 1256 return self.factory.deserialize_app(resp)
Fetch a Bungie application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.crates.Application: A Bungie application.
1260 async def fetch_public_milestone_content( 1261 self, milestone_hash: int, / 1262 ) -> milestones.MilestoneContent: 1263 """Fetch the milestone content given its hash. 1264 1265 Parameters 1266 ---------- 1267 milestone_hash : `int` 1268 The milestone hash. 1269 1270 Returns 1271 ------- 1272 `aiobungie.crates.milestones.MilestoneContent` 1273 A milestone content object. 1274 """ 1275 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1276 1277 return self.factory.deserialize_public_milestone_content(resp)
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.crates.milestones.MilestoneContent: A milestone content object.
779@typing.final 780class ClosedReasons(Flag): 781 """A Flags enumeration representing the reasons why a person can't join this user's fireteam.""" 782 783 NONE = 0 784 MATCHMAKING = 1 << 0 785 LOADING = 1 << 1 786 SOLO = 1 << 2 787 """The activity is required to be played solo.""" 788 INTERNAL_REASONS = 1 << 3 789 """ 790 The user can't be joined for one of a variety of internal reasons. 791 Basically, the game can't let you join at this time, 792 but for reasons that aren't under the control of this user 793 """ 794 DISALLOWED_BY_GAME_STATE = 1 << 4 795 """The user's current activity/quest/other transitory game state is preventing joining.""" 796 OFFLINE = 32768 797 """The user appears offline."""
A Flags enumeration representing the reasons why a person can't join this user's fireteam.
The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user
The user's current activity/quest/other transitory game state is preventing joining.
74@typing.final 75class ComponentFields(enums.Enum): 76 """An enum that provides fields found in a base component response.""" 77 78 PRIVACY = ComponentPrivacy 79 DISABLED = False
An enum that provides fields found in a base component response.
65@typing.final 66class ComponentPrivacy(int, enums.Enum): 67 """An enum the provides privacy settings for profile components.""" 68 69 NONE = 0 70 PUBLIC = 1 71 PRIVATE = 2
An enum the provides privacy settings for profile components.
358@typing.final 359class ComponentType(Enum): 360 """An Enum for Destiny 2 profile Components.""" 361 362 NONE = 0 363 364 PROFILE = 100 365 PROFILE_INVENTORIES = 102 366 PROFILE_CURRENCIES = 103 367 PROFILE_PROGRESSION = 104 368 ALL_PROFILES = ( 369 PROFILE, 370 PROFILE_INVENTORIES, 371 PROFILE_CURRENCIES, 372 PROFILE_PROGRESSION, 373 ) 374 """All profile components.""" 375 376 VENDORS = 400 377 VENDOR_SALES = 402 378 VENDOR_RECEIPTS = 101 379 ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES) 380 """All vendor components.""" 381 382 # Items 383 ITEM_INSTANCES = 300 384 ITEM_OBJECTIVES = 301 385 ITEM_PERKS = 302 386 ITEM_RENDER_DATA = 303 387 ITEM_STATS = 304 388 ITEM_SOCKETS = 305 389 ITEM_TALENT_GRINDS = 306 390 ITEM_PLUG_STATES = 308 391 ITEM_PLUG_OBJECTIVES = 309 392 ITEM_REUSABLE_PLUGS = 310 393 394 ALL_ITEMS = ( 395 ITEM_PLUG_OBJECTIVES, 396 ITEM_PLUG_STATES, 397 ITEM_SOCKETS, 398 ITEM_INSTANCES, 399 ITEM_OBJECTIVES, 400 ITEM_PERKS, 401 ITEM_RENDER_DATA, 402 ITEM_STATS, 403 ITEM_TALENT_GRINDS, 404 ITEM_REUSABLE_PLUGS, 405 ) 406 """All item components.""" 407 408 PLATFORM_SILVER = 105 409 KIOSKS = 500 410 CURRENCY_LOOKUPS = 600 411 PRESENTATION_NODES = 700 412 COLLECTIBLES = 800 413 RECORDS = 900 414 TRANSITORY = 1000 415 METRICS = 1100 416 INVENTORIES = 102 417 STRING_VARIABLES = 1200 418 CRAFTABLES = 1300 419 420 CHARACTERS = 200 421 CHARACTER_INVENTORY = 201 422 CHARECTER_PROGRESSION = 202 423 CHARACTER_RENDER_DATA = 203 424 CHARACTER_ACTIVITIES = 204 425 CHARACTER_EQUIPMENT = 205 426 427 ALL_CHARACTERS = ( 428 CHARACTERS, 429 CHARACTER_INVENTORY, 430 CHARECTER_PROGRESSION, 431 CHARACTER_RENDER_DATA, 432 CHARACTER_ACTIVITIES, 433 CHARACTER_EQUIPMENT, 434 RECORDS, 435 ) 436 """All character components.""" 437 438 ALL = ( 439 *ALL_PROFILES, # type: ignore 440 *ALL_CHARACTERS, # type: ignore 441 *ALL_VENDORS, # type: ignore 442 *ALL_ITEMS, # type: ignore 443 RECORDS, 444 CURRENCY_LOOKUPS, 445 PRESENTATION_NODES, 446 COLLECTIBLES, 447 KIOSKS, 448 METRICS, 449 PLATFORM_SILVER, 450 INVENTORIES, 451 STRING_VARIABLES, 452 TRANSITORY, 453 CRAFTABLES, 454 ) 455 """ALl components included."""
An Enum for Destiny 2 profile Components.
All item components.
All character components.
ALl components included.
661@typing.final 662class CredentialType(int, Enum): 663 """The types of the accounts system supports at bungie.""" 664 665 NONE = 0 666 XUID = 1 667 PSNID = 2 668 WILD = 3 669 FAKE = 4 670 FACEBOOK = 5 671 GOOGLE = 8 672 WINDOWS = 9 673 DEMONID = 10 674 STEAMID = 12 675 BATTLENETID = 14 676 STADIAID = 16 677 TWITCHID = 18
The types of the accounts system supports at bungie.
539@typing.final 540class DamageType(int, Enum): 541 """Enums for Destiny Damage types""" 542 543 NONE = 0 544 KINETIC = 1 545 ARC = 2 546 SOLAR = 3 547 VOID = 4 548 RAID = 5 549 """This is a special damage type reserved for some raid activity encounters.""" 550 STASIS = 6
Enums for Destiny Damage types
This is a special damage type reserved for some raid activity encounters.
64@typing.final 65class Difficulty(int, enums.Enum): 66 """An enum for activities difficulties.""" 67 68 TRIVIAL = 0 69 EASY = 1 70 NORMAL = 2 71 CHALLENGING = 3 72 HARD = 4 73 BRAVE = 5 74 ALMOST_IMPOSSIBLE = 6 75 IMPOSSIBLE = 7
An enum for activities difficulties.
160@typing.final 161class Dungeon(int, Enum): 162 """An Enum for all available Dungeon/Like missions in Destiny 2.""" 163 164 NORMAL_PRESAGE = 2124066889 165 """Normal Presage""" 166 167 MASTER_PRESAGE = 4212753278 168 """Master Presage""" 169 170 HARBINGER = 1738383283 171 """Harbinger""" 172 173 PROPHECY = 4148187374 174 """Prophecy""" 175 176 MASTER_POH = 785700673 177 """Master Pit of Heresy?""" 178 179 LEGEND_POH = 785700678 180 """Legend Pit of Heresy?""" 181 182 POH = 1375089621 183 """Normal Pit of Heresy.""" 184 185 SHATTERED = 2032534090 186 """Shattered Throne""" 187 188 GOA_LEGEND = 4078656646 189 """Grasp of Avarice legend.""" 190 191 GOA_MASTER = 3774021532 192 """Grasp of Avarice master."""
An Enum for all available Dungeon/Like missions in Destiny 2.
72class Enum(__enum.Enum): 73 """Builtin Python enum with extra handlings.""" 74 75 @property 76 def name(self) -> str: # type: ignore[override] 77 return self._name_ 78 79 @property 80 def value(self) -> typing.Any: # type: ignore[override] 81 return self._value_ 82 83 def __str__(self) -> str: 84 return self._name_ 85 86 def __repr__(self) -> str: 87 return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>" 88 89 def __int__(self) -> int: 90 if isinstance(self.value, _ITERABLE): 91 raise TypeError( 92 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 93 ) 94 return int(self.value)
Builtin Python enum with extra handlings.
61class Factory(interfaces.FactoryInterface): 62 """The base deserialization factory class for all aiobungie objects. 63 64 Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them 65 into a `aiobungie.crates` Python classes. 66 """ 67 68 __slots__ = ("_net",) 69 70 def __init__(self, net: traits.Netrunner) -> None: 71 self._net = net 72 73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 ) 96 97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.UNDEFINED), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 ) 113 114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 ) 140 141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data] 145 146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 ) 157 158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 ) 183 184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.UNDEFINED), 193 ) 194 for creds in payload 195 ] 196 197 def deserialize_user_themes( 198 self, payload: typedefs.JSONArray 199 ) -> collections.Sequence[user.UserThemes]: 200 return [ 201 user.UserThemes( 202 id=int(entry["userThemeId"]), 203 name=entry["userThemeName"] 204 if "userThemeName" in entry 205 else undefined.UNDEFINED, 206 description=entry["userThemeDescription"] 207 if "userThemeDescription" in entry 208 else undefined.UNDEFINED, 209 ) 210 for entry in payload 211 ] 212 213 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 214 215 # This is kinda redundant 216 data = payload 217 218 # This is always outside the details. 219 current_user_map: typing.Optional[ 220 collections.Mapping[str, clans.ClanMember] 221 ] = None 222 if raw_current_user_map := payload.get("currentUserMemberMap"): 223 current_user_map = { 224 membership_type: self.deserialize_clan_member(membership) 225 for membership_type, membership in raw_current_user_map.items() 226 } 227 228 try: 229 data = payload["detail"] 230 except KeyError: 231 pass 232 233 id = data["groupId"] 234 name = data["name"] 235 created_at = data["creationDate"] 236 member_count = data["memberCount"] 237 about = data["about"] 238 motto = data["motto"] 239 is_public = data["isPublic"] 240 banner = assets.Image(str(data["bannerPath"])) 241 avatar = assets.Image(str(data["avatarPath"])) 242 tags = data["tags"] 243 type = data["groupType"] 244 245 features = data["features"] 246 features_obj = clans.ClanFeatures( 247 max_members=features["maximumMembers"], 248 max_membership_types=features["maximumMembershipsOfGroupType"], 249 capabilities=features["capabilities"], 250 membership_types=features["membershipTypes"], 251 invite_permissions=features["invitePermissionOverride"], 252 update_banner_permissions=features["updateBannerPermissionOverride"], 253 update_culture_permissions=features["updateCulturePermissionOverride"], 254 join_level=features["joinLevel"], 255 ) 256 257 information: typedefs.JSONObject = data["clanInfo"] 258 progression: collections.Mapping[int, progressions.Progression] = { 259 int(prog_hash): self.deserialize_progressions(prog) 260 for prog_hash, prog in information["d2ClanProgressions"].items() 261 } 262 263 founder: typedefs.NoneOr[clans.ClanMember] = None 264 if raw_founder := payload.get("founder"): 265 founder = self.deserialize_clan_member(raw_founder) 266 267 return clans.Clan( 268 net=self._net, 269 id=int(id), 270 name=name, 271 type=enums.GroupType(type), 272 created_at=time.clean_date(created_at), 273 member_count=member_count, 274 motto=motto, 275 about=about, 276 is_public=is_public, 277 banner=banner, 278 avatar=avatar, 279 tags=tags, 280 features=features_obj, 281 owner=founder, 282 progressions=progression, 283 call_sign=information["clanCallsign"], 284 banner_data=information["clanBannerData"], 285 chat_security=data["chatSecurity"], 286 conversation_id=int(data["conversationId"]), 287 allow_chat=data["allowChat"], 288 theme=data["theme"], 289 current_user_membership=current_user_map, 290 ) 291 292 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 293 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 294 return clans.ClanMember( 295 net=self._net, 296 last_seen_name=destiny_user.last_seen_name, 297 id=destiny_user.id, 298 name=destiny_user.name, 299 icon=destiny_user.icon, 300 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 301 group_id=int(data["groupId"]), 302 joined_at=time.clean_date(data["joinDate"]), 303 types=destiny_user.types, 304 is_public=destiny_user.is_public, 305 type=destiny_user.type, 306 code=destiny_user.code, 307 is_online=data["isOnline"], 308 crossave_override=destiny_user.crossave_override, 309 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 310 if "bungieNetUserInfo" in data 311 else None, 312 member_type=enums.ClanMemberType(int(data["memberType"])), 313 ) 314 315 def deserialize_clan_members( 316 self, data: typedefs.JSONObject, / 317 ) -> iterators.Iterator[clans.ClanMember]: 318 return iterators.Iterator( 319 [self.deserialize_clan_member(member) for member in data["results"]] 320 ) 321 322 def deserialize_group_member( 323 self, payload: typedefs.JSONObject 324 ) -> clans.GroupMember: 325 member = payload["member"] 326 return clans.GroupMember( 327 net=self._net, 328 join_date=time.clean_date(member["joinDate"]), 329 group_id=int(member["groupId"]), 330 member_type=enums.ClanMemberType(member["memberType"]), 331 is_online=member["isOnline"], 332 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 333 inactive_memberships=payload.get("areAllMembershipsInactive", None), 334 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 335 group=self.deserialize_clan(payload["group"]), 336 ) 337 338 def _deserialize_clan_conversation( 339 self, payload: typedefs.JSONObject 340 ) -> clans.ClanConversation: 341 return clans.ClanConversation( 342 net=self._net, 343 id=int(payload["conversationId"]), 344 group_id=int(payload["groupId"]), 345 name=( 346 payload["chatName"] 347 if not typedefs.is_unknown(payload["chatName"]) 348 else undefined.UNDEFINED 349 ), 350 chat_enabled=payload["chatEnabled"], 351 security=payload["chatSecurity"], 352 ) 353 354 def deserialize_clan_conversations( 355 self, payload: typedefs.JSONArray 356 ) -> collections.Sequence[clans.ClanConversation]: 357 return [self._deserialize_clan_conversation(conv) for conv in payload] 358 359 def deserialize_app_owner( 360 self, payload: typedefs.JSONObject 361 ) -> application.ApplicationOwner: 362 return application.ApplicationOwner( 363 net=self._net, 364 name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED), 365 id=int(payload["membershipId"]), 366 type=enums.MembershipType(payload["membershipType"]), 367 icon=assets.Image(str(payload["iconPath"])), 368 is_public=payload["isPublic"], 369 code=payload.get("bungieGlobalDisplayNameCode", None), 370 ) 371 372 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 373 return application.Application( 374 id=int(payload["applicationId"]), 375 name=payload["name"], 376 link=payload["link"], 377 status=payload["status"], 378 redirect_url=payload.get("redirectUrl", None), 379 created_at=time.clean_date(str(payload["creationDate"])), 380 published_at=time.clean_date(str(payload["firstPublished"])), 381 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 382 scope=payload.get("scope", undefined.UNDEFINED), 383 ) 384 385 def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character: 386 total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True) 387 return character.Character( 388 net=self._net, 389 id=int(payload["characterId"]), 390 gender=enums.Gender(payload["genderType"]), 391 race=enums.Race(payload["raceType"]), 392 class_type=enums.Class(payload["classType"]), 393 emblem=assets.Image(str(payload["emblemBackgroundPath"])), 394 emblem_icon=assets.Image(str(payload["emblemPath"])), 395 emblem_hash=int(payload["emblemHash"]), 396 last_played=time.clean_date(payload["dateLastPlayed"]), 397 total_played_time=total_time, 398 member_id=int(payload["membershipId"]), 399 member_type=enums.MembershipType(payload["membershipType"]), 400 level=payload["baseCharacterLevel"], 401 title_hash=payload.get("titleRecordHash", None), 402 light=payload["light"], 403 stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()}, 404 ) 405 406 def deserialize_profile( 407 self, payload: typedefs.JSONObject, / 408 ) -> typing.Optional[profile.Profile]: 409 if (raw_profile := payload.get("data")) is None: 410 return None 411 412 payload = raw_profile 413 id = int(payload["userInfo"]["membershipId"]) 414 name = payload["userInfo"]["displayName"] 415 is_public = payload["userInfo"]["isPublic"] 416 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 417 last_played = time.clean_date(str(payload["dateLastPlayed"])) 418 character_ids = [int(cid) for cid in payload["characterIds"]] 419 power_cap = payload["currentSeasonRewardPowerCap"] 420 421 return profile.Profile( 422 id=int(id), 423 name=name, 424 is_public=is_public, 425 type=type, 426 last_played=last_played, 427 character_ids=character_ids, 428 power_cap=power_cap, 429 net=self._net, 430 ) 431 432 def deserialize_profile_item( 433 self, payload: typedefs.JSONObject 434 ) -> profile.ProfileItemImpl: 435 436 instance_id: typing.Optional[int] = None 437 if raw_instance_id := payload.get("itemInstanceId"): 438 instance_id = int(raw_instance_id) 439 440 version_number: typing.Optional[int] = None 441 if raw_version := payload.get("versionNumber"): 442 version_number = int(raw_version) 443 444 transfer_status = enums.TransferStatus(payload["transferStatus"]) 445 446 return profile.ProfileItemImpl( 447 net=self._net, 448 hash=payload["itemHash"], 449 quantity=payload["quantity"], 450 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 451 location=enums.ItemLocation(payload["location"]), 452 bucket=payload["bucketHash"], 453 transfer_status=transfer_status, 454 lockable=payload["lockable"], 455 state=enums.ItemState(payload["state"]), 456 dismantel_permissions=payload["dismantlePermission"], 457 is_wrapper=payload["isWrapper"], 458 instance_id=instance_id, 459 version_number=version_number, 460 ornament_id=payload.get("overrideStyleItemHash"), 461 ) 462 463 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 464 return records.Objective( 465 net=self._net, 466 hash=payload["objectiveHash"], 467 visible=payload["visible"], 468 complete=payload["complete"], 469 completion_value=payload["completionValue"], 470 progress=payload.get("progress"), 471 destination_hash=payload.get("destinationHash"), 472 activity_hash=payload.get("activityHash"), 473 ) 474 475 def deserialize_records( 476 self, 477 payload: typedefs.JSONObject, 478 scores: typing.Optional[records.RecordScores] = None, 479 **nodes: int, 480 ) -> records.Record: 481 objectives: typing.Optional[list[records.Objective]] = None 482 interval_objectives: typing.Optional[list[records.Objective]] = None 483 record_state: typedefs.IntAnd[records.RecordState] 484 485 record_state = records.RecordState(payload["state"]) 486 487 if raw_objs := payload.get("objectives"): 488 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 489 490 if raw_interval_objs := payload.get("intervalObjectives"): 491 interval_objectives = [ 492 self.deserialize_objectives(obj) for obj in raw_interval_objs 493 ] 494 495 return records.Record( 496 scores=scores, 497 categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED), 498 seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED), 499 state=record_state, 500 objectives=objectives, 501 interval_objectives=interval_objectives, 502 redeemed_count=payload.get("intervalsRedeemedCount", 0), 503 completion_times=payload.get("completedCount", None), 504 reward_visibility=payload.get("rewardVisibilty", None), 505 ) 506 507 def deserialize_character_records( 508 self, 509 payload: typedefs.JSONObject, 510 scores: typing.Optional[records.RecordScores] = None, 511 record_hashes: typing.Optional[list[int]] = None, 512 ) -> records.CharacterRecord: 513 514 record = self.deserialize_records(payload, scores) 515 return records.CharacterRecord( 516 scores=scores, 517 categories_node_hash=record.categories_node_hash, 518 seals_node_hash=record.seals_node_hash, 519 state=record.state, 520 objectives=record.objectives, 521 interval_objectives=record.interval_objectives, 522 redeemed_count=payload.get("intervalsRedeemedCount", 0), 523 completion_times=payload.get("completedCount"), 524 reward_visibility=payload.get("rewardVisibilty"), 525 record_hashes=record_hashes or [], 526 ) 527 528 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 529 return character.Dye( 530 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 531 ) 532 533 def deserialize_character_customization( 534 self, payload: typedefs.JSONObject 535 ) -> character.CustomizationOptions: 536 return character.CustomizationOptions( 537 personality=payload["personality"], 538 face=payload["face"], 539 skin_color=payload["skinColor"], 540 lip_color=payload["lipColor"], 541 eye_color=payload["eyeColor"], 542 hair_colors=payload.get("hairColors", []), 543 feature_colors=payload.get("featureColors", []), 544 decal_color=payload["decalColor"], 545 wear_helmet=payload["wearHelmet"], 546 hair_index=payload["hairIndex"], 547 feature_index=payload["featureIndex"], 548 decal_index=payload["decalIndex"], 549 ) 550 551 def deserialize_character_minimal_equipments( 552 self, payload: typedefs.JSONObject 553 ) -> character.MinimalEquipments: 554 dyes = None 555 if raw_dyes := payload.get("dyes"): 556 if raw_dyes: 557 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 558 return character.MinimalEquipments( 559 net=self._net, item_hash=payload["itemHash"], dyes=dyes 560 ) 561 562 def deserialize_character_render_data( 563 self, payload: typedefs.JSONObject, / 564 ) -> character.RenderedData: 565 return character.RenderedData( 566 net=self._net, 567 customization=self.deserialize_character_customization( 568 payload["customization"] 569 ), 570 custom_dyes=[ 571 self.deserialize_character_dye(dye) 572 for dye in payload["customDyes"] 573 if dye 574 ], 575 equipment=[ 576 self.deserialize_character_minimal_equipments(equipment) 577 for equipment in payload["peerView"]["equipment"] 578 ], 579 ) 580 581 def deserialize_available_activity( 582 self, payload: typedefs.JSONObject 583 ) -> activity.AvailableActivity: 584 return activity.AvailableActivity( 585 hash=payload["activityHash"], 586 is_new=payload["isNew"], 587 is_completed=payload["isCompleted"], 588 is_visible=payload["isVisible"], 589 display_level=payload.get("displayLevel"), 590 recommended_light=payload.get("recommendedLight"), 591 difficulty=activity.Difficulty(payload["difficultyTier"]), 592 can_join=payload["canJoin"], 593 can_lead=payload["canLead"], 594 ) 595 596 def deserialize_character_activity( 597 self, payload: typedefs.JSONObject 598 ) -> activity.CharacterActivity: 599 current_mode: typing.Optional[enums.GameMode] = None 600 if raw_current_mode := payload.get("currentActivityModeType"): 601 current_mode = enums.GameMode(raw_current_mode) 602 603 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 604 if raw_current_modes := payload.get("currentActivityModeTypes"): 605 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 606 607 return activity.CharacterActivity( 608 date_started=time.clean_date(payload["dateActivityStarted"]), 609 current_hash=payload["currentActivityHash"], 610 current_mode_hash=payload["currentActivityModeHash"], 611 current_mode=current_mode, 612 current_mode_hashes=payload.get("currentActivityModeHashes"), 613 current_mode_types=current_mode_types, 614 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 615 last_story_hash=payload["lastCompletedStoryHash"], 616 available_activities=[ 617 self.deserialize_available_activity(activity_) 618 for activity_ in payload["availableActivities"] 619 ], 620 ) 621 622 def deserialize_profile_items( 623 self, payload: typedefs.JSONObject, / 624 ) -> list[profile.ProfileItemImpl]: 625 return [self.deserialize_profile_item(item) for item in payload["items"]] 626 627 def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node: 628 return records.Node( 629 state=int(payload["state"]), 630 objective=self.deserialize_objectives(payload["objective"]) 631 if "objective" in payload 632 else None, 633 progress_value=int(payload["progressValue"]), 634 completion_value=int(payload["completionValue"]), 635 record_category_score=int(payload["recordCategoryScore"]) 636 if "recordCategoryScore" in payload 637 else None, 638 ) 639 640 @staticmethod 641 def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible: 642 recent_collectibles: typing.Optional[collections.Collection[int]] = None 643 if raw_recent_collectibles := payload.get("recentCollectibleHashes"): 644 recent_collectibles = [ 645 int(item_hash) for item_hash in raw_recent_collectibles 646 ] 647 648 collectibles: dict[int, int] = {} 649 for item_hash, mapping in payload["collectibles"].items(): 650 collectibles[int(item_hash)] = int(mapping["state"]) 651 652 return items.Collectible( 653 recent_collectibles=recent_collectibles, 654 collectibles=collectibles, 655 collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]), 656 collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]), 657 ) 658 659 @staticmethod 660 def _deserialize_currencies( 661 payload: typedefs.JSONObject, 662 ) -> collections.Sequence[items.Currency]: 663 return [ 664 items.Currency(hash=int(item_hash), amount=int(amount)) 665 for item_hash, amount in payload["itemQuantities"].items() 666 ] 667 668 def deserialize_progressions( 669 self, payload: typedefs.JSONObject 670 ) -> progressions.Progression: 671 return progressions.Progression( 672 hash=int(payload["progressionHash"]), 673 level=int(payload["level"]), 674 cap=int(payload["levelCap"]), 675 daily_limit=int(payload["dailyLimit"]), 676 weekly_limit=int(payload["weeklyLimit"]), 677 current_progress=int(payload["currentProgress"]), 678 daily_progress=int(payload["dailyProgress"]), 679 needed=int(payload["progressToNextLevel"]), 680 next_level=int(payload["nextLevelAt"]), 681 ) 682 683 def _deserialize_factions( 684 self, payload: typedefs.JSONObject 685 ) -> progressions.Factions: 686 progs = self.deserialize_progressions(payload) 687 return progressions.Factions( 688 hash=progs.hash, 689 level=progs.level, 690 cap=progs.cap, 691 daily_limit=progs.daily_limit, 692 weekly_limit=progs.weekly_limit, 693 current_progress=progs.current_progress, 694 daily_progress=progs.daily_progress, 695 needed=progs.needed, 696 next_level=progs.next_level, 697 faction_hash=payload["factionHash"], 698 faction_vendor_hash=payload["factionVendorIndex"], 699 ) 700 701 def _deserialize_milestone_available_quest( 702 self, payload: typedefs.JSONObject 703 ) -> milestones.MilestoneQuest: 704 return milestones.MilestoneQuest( 705 item_hash=payload["questItemHash"], 706 status=self._deserialize_milestone_quest_status(payload["status"]), 707 ) 708 709 def _deserialize_milestone_activity( 710 self, payload: typedefs.JSONObject 711 ) -> milestones.MilestoneActivity: 712 713 phases: typing.Optional[ 714 collections.Sequence[milestones.MilestoneActivityPhase] 715 ] = None 716 if raw_phases := payload.get("phases"): 717 phases = [ 718 milestones.MilestoneActivityPhase( 719 is_completed=obj["complete"], hash=obj["phaseHash"] 720 ) 721 for obj in raw_phases 722 ] 723 724 return milestones.MilestoneActivity( 725 hash=payload["activityHash"], 726 challenges=[ 727 self.deserialize_objectives(obj["objective"]) 728 for obj in payload["challenges"] 729 ], 730 modifier_hashes=payload.get("modifierHashes"), 731 boolean_options=payload.get("booleanActivityOptions"), 732 phases=phases, 733 ) 734 735 def _deserialize_milestone_quest_status( 736 self, payload: typedefs.JSONObject 737 ) -> milestones.QuestStatus: 738 return milestones.QuestStatus( 739 net=self._net, 740 quest_hash=payload["questHash"], 741 step_hash=payload["stepHash"], 742 step_objectives=[ 743 self.deserialize_objectives(objective) 744 for objective in payload["stepObjectives"] 745 ], 746 is_tracked=payload["tracked"], 747 is_completed=payload["completed"], 748 started=payload["started"], 749 item_instance_id=payload["itemInstanceId"], 750 vendor_hash=payload.get("vendorHash"), 751 is_redeemed=payload["redeemed"], 752 ) 753 754 def _deserialize_milestone_rewards( 755 self, payload: typedefs.JSONObject 756 ) -> milestones.MilestoneReward: 757 return milestones.MilestoneReward( 758 category_hash=payload["rewardCategoryHash"], 759 entries=[ 760 milestones.MilestoneRewardEntry( 761 entry_hash=entry["rewardEntryHash"], 762 is_earned=entry["earned"], 763 is_redeemed=entry["redeemed"], 764 ) 765 for entry in payload["entries"] 766 ], 767 ) 768 769 def deserialize_milestone( 770 self, payload: typedefs.JSONObject 771 ) -> milestones.Milestone: 772 start_date: typing.Optional[datetime.datetime] = None 773 if raw_start_date := payload.get("startDate"): 774 start_date = time.clean_date(raw_start_date) 775 776 end_date: typing.Optional[datetime.datetime] = None 777 if raw_end_date := payload.get("endDate"): 778 end_date = time.clean_date(raw_end_date) 779 780 rewards: typing.Optional[ 781 collections.Collection[milestones.MilestoneReward] 782 ] = None 783 if raw_rewards := payload.get("rewards"): 784 rewards = [ 785 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 786 ] 787 788 activities: typing.Optional[ 789 collections.Sequence[milestones.MilestoneActivity] 790 ] = None 791 if raw_activities := payload.get("activities"): 792 activities = [ 793 self._deserialize_milestone_activity(active) 794 for active in raw_activities 795 ] 796 797 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 798 if raw_quests := payload.get("availableQuests"): 799 quests = [ 800 self._deserialize_milestone_available_quest(quest) 801 for quest in raw_quests 802 ] 803 804 vendors: typing.Optional[ 805 collections.Sequence[milestones.MilestoneVendor] 806 ] = None 807 if raw_vendors := payload.get("vendors"): 808 vendors = [ 809 milestones.MilestoneVendor( 810 vendor_hash=vendor["vendorHash"], 811 preview_itemhash=vendor.get("previewItemHash"), 812 ) 813 for vendor in raw_vendors 814 ] 815 816 return milestones.Milestone( 817 hash=payload["milestoneHash"], 818 start_date=start_date, 819 end_date=end_date, 820 order=payload["order"], 821 rewards=rewards, 822 available_quests=quests, 823 activities=activities, 824 vendors=vendors, 825 ) 826 827 def _deserialize_artifact_tiers( 828 self, payload: typedefs.JSONObject 829 ) -> season.ArtifactTier: 830 return season.ArtifactTier( 831 hash=payload["tierHash"], 832 is_unlocked=payload["isUnlocked"], 833 points_to_unlock=payload["pointsToUnlock"], 834 items=[ 835 season.ArtifactTierItem( 836 hash=item["itemHash"], is_active=item["isActive"] 837 ) 838 for item in payload["items"] 839 ], 840 ) 841 842 def deserialize_characters( 843 self, payload: typedefs.JSONObject 844 ) -> collections.Mapping[int, character.Character]: 845 return { 846 int(char_id): self._set_character_attrs(char) 847 for char_id, char in payload["data"].items() 848 } 849 850 def deserialize_character( 851 self, payload: typedefs.JSONObject 852 ) -> character.Character: 853 return self._set_character_attrs(payload) 854 855 def deserialize_character_equipments( 856 self, payload: typedefs.JSONObject 857 ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]: 858 return { 859 int(char_id): self.deserialize_profile_items(item) 860 for char_id, item in payload["data"].items() 861 } 862 863 def deserialize_character_activities( 864 self, payload: typedefs.JSONObject 865 ) -> collections.Mapping[int, activity.CharacterActivity]: 866 return { 867 int(char_id): self.deserialize_character_activity(data) 868 for char_id, data in payload["data"].items() 869 } 870 871 def deserialize_characters_render_data( 872 self, payload: typedefs.JSONObject 873 ) -> collections.Mapping[int, character.RenderedData]: 874 return { 875 int(char_id): self.deserialize_character_render_data(data) 876 for char_id, data in payload["data"].items() 877 } 878 879 def deserialize_character_progressions( 880 self, payload: typedefs.JSONObject 881 ) -> character.CharacterProgression: 882 progressions_ = { 883 int(prog_id): self.deserialize_progressions(prog) 884 for prog_id, prog in payload["progressions"].items() 885 } 886 887 factions = { 888 int(faction_id): self._deserialize_factions(faction) 889 for faction_id, faction in payload["factions"].items() 890 } 891 892 milestones_ = { 893 int(milestone_hash): self.deserialize_milestone(milestone) 894 for milestone_hash, milestone in payload["milestones"].items() 895 } 896 897 uninstanced_item_objectives = { 898 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 899 for item_hash, obj in payload["uninstancedItemObjectives"].items() 900 } 901 902 artifact = payload["seasonalArtifact"] 903 seasonal_artifact = season.CharacterScopedArtifact( 904 hash=artifact["artifactHash"], 905 points_used=artifact["pointsUsed"], 906 reset_count=artifact["resetCount"], 907 tiers=[ 908 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 909 ], 910 ) 911 checklists = payload["checklists"] 912 913 return character.CharacterProgression( 914 progressions=progressions_, 915 factions=factions, 916 checklists=checklists, 917 milestones=milestones_, 918 seasonal_artifact=seasonal_artifact, 919 uninstanced_item_objectives=uninstanced_item_objectives, 920 ) 921 922 def deserialize_character_progressions_mapping( 923 self, payload: typedefs.JSONObject 924 ) -> collections.Mapping[int, character.CharacterProgression]: 925 character_progressions: collections.Mapping[ 926 int, character.CharacterProgression 927 ] = {} 928 for char_id, data in payload["data"].items(): 929 # A little hack to stop mypy complaining about Mapping <-> dict 930 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 931 return character_progressions 932 933 def deserialize_characters_records( 934 self, 935 payload: typedefs.JSONObject, 936 ) -> collections.Mapping[int, records.CharacterRecord]: 937 938 return { 939 int(rec_id): self.deserialize_character_records( 940 rec, record_hashes=payload.get("featuredRecordHashes") 941 ) 942 for rec_id, rec in payload["records"].items() 943 } 944 945 def deserialize_profile_records( 946 self, payload: typedefs.JSONObject 947 ) -> collections.Mapping[int, records.Record]: 948 raw_profile_records = payload["data"] 949 scores = records.RecordScores( 950 current_score=raw_profile_records["score"], 951 legacy_score=raw_profile_records["legacyScore"], 952 lifetime_score=raw_profile_records["lifetimeScore"], 953 ) 954 return { 955 int(record_id): self.deserialize_records( 956 record, 957 scores, 958 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 959 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 960 ) 961 for record_id, record in raw_profile_records["records"].items() 962 } 963 964 def _deserialize_craftable_socket_plug( 965 self, payload: typedefs.JSONObject 966 ) -> items.CraftableSocketPlug: 967 return items.CraftableSocketPlug( 968 item_hash=int(payload["plugItemHash"]), 969 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 970 ) 971 972 def _deserialize_craftable_socket( 973 self, payload: typedefs.JSONObject 974 ) -> items.CraftableSocket: 975 976 plugs: list[items.CraftableSocketPlug] = [] 977 if raw_plug := payload.get("plug"): 978 plugs.extend( 979 self._deserialize_craftable_socket_plug(plug) for plug in raw_plug 980 ) 981 982 return items.CraftableSocket( 983 plug_set_hash=int(payload["plugSetHash"]), plugs=plugs 984 ) 985 986 def _deserialize_craftable_item( 987 self, payload: typedefs.JSONObject 988 ) -> items.CraftableItem: 989 990 return items.CraftableItem( 991 is_visible=payload["visible"], 992 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 993 sockets=[ 994 self._deserialize_craftable_socket(socket) 995 for socket in payload["sockets"] 996 ], 997 ) 998 999 def deserialize_craftables_component( 1000 self, payload: typedefs.JSONObject 1001 ) -> components.CraftablesComponent: 1002 return components.CraftablesComponent( 1003 net=self._net, 1004 craftables={ 1005 int(item_id): self._deserialize_craftable_item(item) 1006 for item_id, item in payload["craftables"].items() 1007 if item is not None 1008 }, 1009 crafting_root_node_hash=payload["craftingRootNodeHash"], 1010 ) 1011 1012 def deserialize_components( # noqa: C901 Too complex. 1013 self, payload: typedefs.JSONObject 1014 ) -> components.Component: 1015 1016 profile_: typing.Optional[profile.Profile] = None 1017 if raw_profile := payload.get("profile"): 1018 profile_ = self.deserialize_profile(raw_profile) 1019 1020 profile_progression: typing.Optional[profile.ProfileProgression] = None 1021 if raw_profile_progression := payload.get("profileProgression"): 1022 profile_progression = self.deserialize_profile_progression( 1023 raw_profile_progression 1024 ) 1025 1026 profile_currencies: typing.Optional[ 1027 collections.Sequence[profile.ProfileItemImpl] 1028 ] = None 1029 if raw_profile_currencies := payload.get("profileCurrencies"): 1030 if "data" in raw_profile_currencies: 1031 profile_currencies = self.deserialize_profile_items( 1032 raw_profile_currencies["data"] 1033 ) 1034 1035 profile_inventories: typing.Optional[ 1036 collections.Sequence[profile.ProfileItemImpl] 1037 ] = None 1038 if raw_profile_inventories := payload.get("profileInventory"): 1039 if "data" in raw_profile_inventories: 1040 profile_inventories = self.deserialize_profile_items( 1041 raw_profile_inventories["data"] 1042 ) 1043 1044 profile_records: typing.Optional[ 1045 collections.Mapping[int, records.Record] 1046 ] = None 1047 1048 if raw_profile_records_ := payload.get("profileRecords"): 1049 profile_records = self.deserialize_profile_records(raw_profile_records_) 1050 1051 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1052 if raw_characters := payload.get("characters"): 1053 characters = self.deserialize_characters(raw_characters) 1054 1055 character_records: typing.Optional[ 1056 collections.Mapping[int, records.CharacterRecord] 1057 ] = None 1058 1059 if raw_character_records := payload.get("characterRecords"): 1060 # Had to do it in two steps.. 1061 to_update: typedefs.JSONObject = {} 1062 for _, data in raw_character_records["data"].items(): 1063 for record_id, record in data.items(): 1064 to_update[record_id] = record 1065 1066 character_records = { 1067 int(rec_id): self.deserialize_character_records( 1068 rec, record_hashes=to_update.get("featuredRecordHashes") 1069 ) 1070 for rec_id, rec in to_update["records"].items() 1071 } 1072 1073 character_equipments: typing.Optional[ 1074 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1075 ] = None 1076 if raw_character_equips := payload.get("characterEquipment"): 1077 character_equipments = self.deserialize_character_equipments( 1078 raw_character_equips 1079 ) 1080 1081 character_inventories: typing.Optional[ 1082 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1083 ] = None 1084 if raw_character_inventories := payload.get("characterInventories"): 1085 if "data" in raw_character_inventories: 1086 character_inventories = self.deserialize_character_equipments( 1087 raw_character_inventories 1088 ) 1089 1090 character_activities: typing.Optional[ 1091 collections.Mapping[int, activity.CharacterActivity] 1092 ] = None 1093 if raw_char_acts := payload.get("characterActivities"): 1094 character_activities = self.deserialize_character_activities(raw_char_acts) 1095 1096 character_render_data: typing.Optional[ 1097 collections.Mapping[int, character.RenderedData] 1098 ] = None 1099 if raw_character_render_data := payload.get("characterRenderData"): 1100 character_render_data = self.deserialize_characters_render_data( 1101 raw_character_render_data 1102 ) 1103 1104 character_progressions: typing.Optional[ 1105 collections.Mapping[int, character.CharacterProgression] 1106 ] = None 1107 1108 if raw_character_progressions := payload.get("characterProgressions"): 1109 character_progressions = self.deserialize_character_progressions_mapping( 1110 raw_character_progressions 1111 ) 1112 1113 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1114 if raw_profile_string_vars := payload.get("profileStringVariables"): 1115 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1116 1117 character_string_vars: typing.Optional[ 1118 collections.Mapping[int, collections.Mapping[int, int]] 1119 ] = None 1120 if raw_character_string_vars := payload.get("characterStringVariables"): 1121 character_string_vars = { 1122 int(char_id): data["integerValuesByHash"] 1123 for char_id, data in raw_character_string_vars["data"].items() 1124 } 1125 1126 metrics: typing.Optional[ 1127 collections.Sequence[ 1128 collections.Mapping[ 1129 int, tuple[bool, typing.Optional[records.Objective]] 1130 ] 1131 ] 1132 ] = None 1133 root_node_hash: typing.Optional[int] = None 1134 1135 if raw_metrics := payload.get("metrics"): 1136 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1137 metrics = [ 1138 { 1139 int(metrics_hash): ( 1140 data["invisible"], 1141 self.deserialize_objectives(data["objectiveProgress"]) 1142 if "objectiveProgress" in data 1143 else None, 1144 ) 1145 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1146 } 1147 ] 1148 transitory: typing.Optional[fireteams.FireteamParty] = None 1149 if raw_transitory := payload.get("profileTransitoryData"): 1150 if "data" in raw_transitory: 1151 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1152 1153 item_components: typing.Optional[components.ItemsComponent] = None 1154 if raw_item_components := payload.get("itemComponents"): 1155 item_components = self.deserialize_items_component(raw_item_components) 1156 1157 profile_plugsets: typing.Optional[ 1158 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1159 ] = None 1160 1161 if raw_profile_plugs := payload.get("profilePlugSets"): 1162 profile_plugsets = { 1163 int(index): [self.deserialize_plug_item_state(state) for state in data] 1164 for index, data in raw_profile_plugs["data"]["plugs"].items() 1165 } 1166 1167 character_plugsets: typing.Optional[ 1168 collections.Mapping[ 1169 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1170 ] 1171 ] = None 1172 if raw_char_plugsets := payload.get("characterPlugSets"): 1173 character_plugsets = { 1174 int(char_id): { 1175 int(index): [ 1176 self.deserialize_plug_item_state(state) for state in data 1177 ] 1178 for index, data in inner["plugs"].items() 1179 } 1180 for char_id, inner in raw_char_plugsets["data"].items() 1181 } 1182 1183 character_collectibles: typing.Optional[ 1184 collections.Mapping[int, items.Collectible] 1185 ] = None 1186 if raw_character_collectibles := payload.get("characterCollectibles"): 1187 character_collectibles = { 1188 int(char_id): self._deserialize_collectible(data) 1189 for char_id, data in raw_character_collectibles["data"].items() 1190 } 1191 1192 profile_collectibles: typing.Optional[items.Collectible] = None 1193 if raw_profile_collectibles := payload.get("profileCollectibles"): 1194 profile_collectibles = self._deserialize_collectible( 1195 raw_profile_collectibles["data"] 1196 ) 1197 1198 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1199 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1200 profile_nodes = { 1201 int(node_hash): self._deserialize_node(node) 1202 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1203 } 1204 1205 character_nodes: typing.Optional[ 1206 collections.Mapping[int, collections.Mapping[int, records.Node]] 1207 ] = None 1208 if raw_character_nodes := payload.get("characterPresentationNodes"): 1209 character_nodes = { 1210 int(char_id): { 1211 int(node_hash): self._deserialize_node(node) 1212 for node_hash, node in each_character["nodes"].items() 1213 } 1214 for char_id, each_character in raw_character_nodes["data"].items() 1215 } 1216 1217 platform_silver: typing.Optional[ 1218 collections.Mapping[str, profile.ProfileItemImpl] 1219 ] = None 1220 if raw_platform_silver := payload.get("platformSilver"): 1221 if "data" in raw_platform_silver: 1222 platform_silver = { 1223 platform_name: self.deserialize_profile_item(item) 1224 for platform_name, item in raw_platform_silver["data"][ 1225 "platformSilver" 1226 ].items() 1227 } 1228 1229 character_currency_lookups: typing.Optional[ 1230 collections.Mapping[int, collections.Sequence[items.Currency]] 1231 ] = None 1232 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1233 if "data" in raw_char_lookups: 1234 character_currency_lookups = { 1235 int(char_id): self._deserialize_currencies(currencie) 1236 for char_id, currencie in raw_char_lookups["data"].items() 1237 } 1238 1239 character_craftables: typing.Optional[ 1240 collections.Mapping[int, components.CraftablesComponent] 1241 ] = None 1242 if raw_character_craftables := payload.get("characterCraftables"): 1243 1244 if "data" in raw_character_craftables: 1245 character_craftables = { 1246 int(char_id): self.deserialize_craftables_component(craftable) 1247 for char_id, craftable in raw_character_craftables["data"].items() 1248 } 1249 1250 return components.Component( 1251 profiles=profile_, 1252 profile_progression=profile_progression, 1253 profile_currencies=profile_currencies, 1254 profile_inventories=profile_inventories, 1255 profile_records=profile_records, 1256 characters=characters, 1257 character_records=character_records, 1258 character_equipments=character_equipments, 1259 character_inventories=character_inventories, 1260 character_activities=character_activities, 1261 character_render_data=character_render_data, 1262 character_progressions=character_progressions, 1263 profile_string_variables=profile_string_vars, 1264 character_string_variables=character_string_vars, 1265 metrics=metrics, 1266 root_node_hash=root_node_hash, 1267 transitory=transitory, 1268 item_components=item_components, 1269 profile_plugsets=profile_plugsets, 1270 character_plugsets=character_plugsets, 1271 character_collectibles=character_collectibles, 1272 profile_collectibles=profile_collectibles, 1273 profile_nodes=profile_nodes, 1274 character_nodes=character_nodes, 1275 platform_silver=platform_silver, 1276 character_currency_lookups=character_currency_lookups, 1277 character_craftables=character_craftables, 1278 ) 1279 1280 def deserialize_items_component( 1281 self, payload: typedefs.JSONObject 1282 ) -> components.ItemsComponent: 1283 instances: typing.Optional[ 1284 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1285 ] = None 1286 if raw_instances := payload.get("instances"): 1287 instances = [ 1288 { 1289 int(ins_id): self.deserialize_instanced_item(item) 1290 for ins_id, item in raw_instances["data"].items() 1291 } 1292 ] 1293 1294 render_data: typing.Optional[ 1295 collections.Mapping[int, tuple[bool, dict[int, int]]] 1296 ] = None 1297 if raw_render_data := payload.get("renderData"): 1298 render_data = { 1299 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1300 for ins_id, data in raw_render_data["data"].items() 1301 } 1302 1303 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1304 if raw_stats := payload.get("stats"): 1305 builder: collections.Mapping[int, items.ItemStatsView] = {} 1306 for ins_id, stat in raw_stats["data"].items(): 1307 for _, items_ in stat.items(): 1308 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1309 stats = builder 1310 1311 sockets: typing.Optional[ 1312 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1313 ] = None 1314 if raw_sockets := payload.get("sockets"): 1315 sockets = { 1316 int(ins_id): [ 1317 self.deserialize_item_socket(socket) for socket in item["sockets"] 1318 ] 1319 for ins_id, item in raw_sockets["data"].items() 1320 } 1321 1322 objeectives: typing.Optional[ 1323 collections.Mapping[int, collections.Sequence[records.Objective]] 1324 ] = None 1325 if raw_objectives := payload.get("objectives"): 1326 objeectives = { 1327 int(ins_id): [self.deserialize_objectives(objective)] 1328 for ins_id, data in raw_objectives["data"].items() 1329 for objective in data["objectives"] 1330 } 1331 1332 perks: typing.Optional[ 1333 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1334 ] = None 1335 if raw_perks := payload.get("perks"): 1336 perks = { 1337 int(ins_id): [ 1338 self.deserialize_item_perk(perk) for perk in item["perks"] 1339 ] 1340 for ins_id, item in raw_perks["data"].items() 1341 } 1342 1343 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1344 if raw_plug_states := payload.get("plugStates"): 1345 pending_states: list[items.PlugItemState] = [] 1346 for _, plug in raw_plug_states["data"].items(): 1347 pending_states.append(self.deserialize_plug_item_state(plug)) 1348 plug_states = pending_states 1349 1350 reusable_plugs: typing.Optional[ 1351 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1352 ] = None 1353 if raw_re_plugs := payload.get("reusablePlugs"): 1354 reusable_plugs = { 1355 int(ins_id): [ 1356 self.deserialize_plug_item_state(state) for state in inner 1357 ] 1358 for ins_id, plug in raw_re_plugs["data"].items() 1359 for inner in list(plug["plugs"].values()) 1360 } 1361 1362 plug_objectives: typing.Optional[ 1363 collections.Mapping[ 1364 int, collections.Mapping[int, collections.Collection[records.Objective]] 1365 ] 1366 ] = None 1367 if raw_plug_objectives := payload.get("plugObjectives"): 1368 plug_objectives = { 1369 int(ins_id): { 1370 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1371 for obj_hash, objs in inner["objectivesPerPlug"].items() 1372 } 1373 for ins_id, inner in raw_plug_objectives["data"].items() 1374 } 1375 1376 return components.ItemsComponent( 1377 sockets=sockets, 1378 stats=stats, 1379 render_data=render_data, 1380 instances=instances, 1381 objectives=objeectives, 1382 perks=perks, 1383 plug_states=plug_states, 1384 reusable_plugs=reusable_plugs, 1385 plug_objectives=plug_objectives, 1386 ) 1387 1388 def deserialize_character_component( # type: ignore[call-arg] 1389 self, payload: typedefs.JSONObject 1390 ) -> components.CharacterComponent: 1391 1392 character_: typing.Optional[character.Character] = None 1393 if raw_singuler_character := payload.get("character"): 1394 character_ = self.deserialize_character(raw_singuler_character["data"]) 1395 1396 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1397 if raw_inventory := payload.get("inventory"): 1398 if "data" in raw_inventory: 1399 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1400 1401 activities: typing.Optional[activity.CharacterActivity] = None 1402 if raw_activities := payload.get("activities"): 1403 activities = self.deserialize_character_activity(raw_activities["data"]) 1404 1405 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1406 if raw_equipments := payload.get("equipment"): 1407 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1408 1409 progressions_: typing.Optional[character.CharacterProgression] = None 1410 if raw_progressions := payload.get("progressions"): 1411 progressions_ = self.deserialize_character_progressions( 1412 raw_progressions["data"] 1413 ) 1414 1415 render_data: typing.Optional[character.RenderedData] = None 1416 if raw_render_data := payload.get("renderData"): 1417 render_data = self.deserialize_character_render_data( 1418 raw_render_data["data"] 1419 ) 1420 1421 character_records: typing.Optional[ 1422 collections.Mapping[int, records.CharacterRecord] 1423 ] = None 1424 if raw_char_records := payload.get("records"): 1425 character_records = self.deserialize_characters_records( 1426 raw_char_records["data"] 1427 ) 1428 1429 item_components: typing.Optional[components.ItemsComponent] = None 1430 if raw_item_components := payload.get("itemComponents"): 1431 item_components = self.deserialize_items_component(raw_item_components) 1432 1433 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1434 if raw_nodes := payload.get("presentationNodes"): 1435 nodes = { 1436 int(node_hash): self._deserialize_node(node) 1437 for node_hash, node in raw_nodes["data"]["nodes"].items() 1438 } 1439 1440 collectibles: typing.Optional[items.Collectible] = None 1441 if raw_collectibles := payload.get("collectibles"): 1442 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1443 1444 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1445 if raw_currencies := payload.get("currencyLookups"): 1446 if "data" in raw_currencies: 1447 currency_lookups = self._deserialize_currencies(raw_currencies) 1448 1449 return components.CharacterComponent( 1450 activities=activities, 1451 equipment=equipment, 1452 inventory=inventory, 1453 progressions=progressions_, 1454 render_data=render_data, 1455 character=character_, 1456 character_records=character_records, 1457 profile_records=None, 1458 item_components=item_components, 1459 currency_lookups=currency_lookups, 1460 collectibles=collectibles, 1461 nodes=nodes, 1462 ) 1463 1464 def _set_entity_attrs( 1465 self, payload: typedefs.JSONObject, *, key: str = "displayProperties" 1466 ) -> entity.Entity: 1467 1468 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1469 description: undefined.UndefinedOr[str] = undefined.UNDEFINED 1470 1471 if properties := payload[key]: 1472 if (raw_name := properties["name"]) is not typedefs.Unknown: 1473 name = raw_name 1474 1475 if ( 1476 raw_description := properties["description"] 1477 ) and not typedefs.is_unknown(raw_description): 1478 description = raw_description 1479 1480 return entity.Entity( 1481 net=self._net, 1482 hash=payload["hash"], 1483 index=payload["index"], 1484 name=name, 1485 description=description, 1486 has_icon=properties["hasIcon"], 1487 icon=assets.Image(properties["icon"] if "icon" in properties else None), 1488 ) 1489 1490 def deserialize_inventory_results( 1491 self, payload: typedefs.JSONObject 1492 ) -> iterators.Iterator[entity.SearchableEntity]: 1493 suggested_words: list[str] = payload["suggestedWords"] 1494 1495 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1496 return s if not typedefs.is_unknown(s) else undefined.UNDEFINED 1497 1498 return iterators.Iterator( 1499 [ 1500 entity.SearchableEntity( 1501 net=self._net, 1502 hash=data["hash"], 1503 entity_type=data["entityType"], 1504 weight=data["weight"], 1505 suggested_words=suggested_words, 1506 name=data["displayProperties"]["name"], 1507 has_icon=data["displayProperties"]["hasIcon"], 1508 description=_check_unknown( 1509 data["displayProperties"]["description"] 1510 ), 1511 icon=assets.Image(data["displayProperties"]["icon"]), 1512 ) 1513 for data in payload["results"]["results"] 1514 ] 1515 ) 1516 1517 def _deserialize_inventory_item_objects( 1518 self, payload: typedefs.JSONObject 1519 ) -> entity.InventoryEntityObjects: 1520 return entity.InventoryEntityObjects( 1521 action=payload.get("action"), 1522 set_data=payload.get("setData"), 1523 stats=payload.get("stats"), 1524 equipping_block=payload.get("equippingBlock"), 1525 translation_block=payload.get("translationBlock"), 1526 preview=payload.get("preview"), 1527 quality=payload.get("quality"), 1528 value=payload.get("value"), 1529 source_data=payload.get("sourceData"), 1530 objectives=payload.get("objectives"), 1531 plug=payload.get("plug"), 1532 metrics=payload.get("metrics"), 1533 gearset=payload.get("gearset"), 1534 sack=payload.get("sack"), 1535 sockets=payload.get("sockets"), 1536 summary=payload.get("summary"), 1537 talent_gird=payload.get("talentGrid"), 1538 investments_stats=payload.get("investmentStats"), 1539 perks=payload.get("perks"), 1540 animations=payload.get("animations", []), 1541 links=payload.get("links", []), 1542 ) 1543 1544 def deserialize_inventory_entity( # noqa: C901 Too complex. 1545 self, payload: typedefs.JSONObject, / 1546 ) -> entity.InventoryEntity: 1547 1548 props = self._set_entity_attrs(payload) 1549 objects = self._deserialize_inventory_item_objects(payload) 1550 1551 collectible_hash: typing.Optional[int] = None 1552 if raw_collectible_hash := payload.get("collectibleHash"): 1553 collectible_hash = int(raw_collectible_hash) 1554 1555 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1556 if raw_second_icon := payload.get("secondaryIcon"): 1557 secondary_icon = assets.Image(raw_second_icon) 1558 1559 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1560 if raw_second_overlay := payload.get("secondaryOverlay"): 1561 secondary_overlay = assets.Image(raw_second_overlay) 1562 1563 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1564 if raw_second_special := payload.get("secondarySpecial"): 1565 secondary_special = assets.Image(raw_second_special) 1566 1567 screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1568 if raw_screenshot := payload.get("screenshot"): 1569 screenshot = assets.Image(raw_screenshot) 1570 1571 watermark_icon: typing.Optional[assets.Image] = None 1572 if raw_watermark_icon := payload.get("iconWatermark"): 1573 watermark_icon = assets.Image(raw_watermark_icon) 1574 1575 watermark_shelved: typing.Optional[assets.Image] = None 1576 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1577 watermark_shelved = assets.Image(raw_watermark_shelved) 1578 1579 about: undefined.UndefinedOr[str] = undefined.UNDEFINED 1580 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1581 raw_about 1582 ): 1583 about = raw_about 1584 1585 ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED 1586 if ( 1587 raw_ui_style := payload.get("uiItemDisplayStyle") 1588 ) and not typedefs.is_unknown(raw_ui_style): 1589 ui_item_style = raw_ui_style 1590 1591 tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1592 if ( 1593 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1594 ) and not typedefs.is_unknown(raw_tier_and_name): 1595 tier_and_name = raw_tier_and_name 1596 1597 type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1598 if ( 1599 raw_type_name := payload.get("itemTypeDisplayName") 1600 ) and not typedefs.is_unknown(raw_type_name): 1601 type_name = raw_type_name 1602 1603 display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED 1604 if ( 1605 raw_display_source := payload.get("displaySource") 1606 ) and not typedefs.is_unknown(raw_display_source): 1607 display_source = raw_display_source 1608 1609 lorehash: typing.Optional[int] = None 1610 if raw_lore_hash := payload.get("loreHash"): 1611 lorehash = int(raw_lore_hash) 1612 1613 summary_hash: typing.Optional[int] = None 1614 if raw_summary_hash := payload.get("summaryItemHash"): 1615 summary_hash = raw_summary_hash 1616 1617 breaker_type_hash: typing.Optional[int] = None 1618 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1619 breaker_type_hash = int(raw_breaker_type_hash) 1620 1621 damage_types: typing.Optional[collections.Sequence[int]] = None 1622 if raw_damage_types := payload.get("damageTypes"): 1623 damage_types = [int(type_) for type_ in raw_damage_types] 1624 1625 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1626 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1627 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1628 1629 default_damagetype_hash: typing.Optional[int] = None 1630 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1631 default_damagetype_hash = int(raw_defaultdmg_hash) 1632 1633 emblem_objective_hash: typing.Optional[int] = None 1634 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1635 emblem_objective_hash = int(raw_emblem_obj_hash) 1636 1637 tier_type: typing.Optional[enums.TierType] = None 1638 tier: typing.Optional[enums.ItemTier] = None 1639 bucket_hash: typing.Optional[int] = None 1640 recovery_hash: typing.Optional[int] = None 1641 tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1642 isinstance_item: bool = False 1643 expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED 1644 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED 1645 suppress_expiration: bool = False 1646 max_stack_size: typing.Optional[int] = None 1647 stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED 1648 1649 if inventory := payload.get("inventory"): 1650 tier_type = enums.TierType(int(inventory["tierType"])) 1651 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1652 bucket_hash = int(inventory["bucketTypeHash"]) 1653 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1654 tier_name = inventory["tierTypeName"] 1655 isinstance_item = inventory["isInstanceItem"] 1656 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1657 max_stack_size = int(inventory["maxStackSize"]) 1658 1659 try: 1660 stack_label = inventory["stackUniqueLabel"] 1661 except KeyError: 1662 pass 1663 1664 return entity.InventoryEntity( 1665 net=self._net, 1666 collectible_hash=collectible_hash, 1667 name=props.name, 1668 about=about, 1669 emblem_objective_hash=emblem_objective_hash, 1670 suppress_expiration=suppress_expiration, 1671 max_stack_size=max_stack_size, 1672 stack_label=stack_label, 1673 tier=tier, 1674 tier_type=tier_type, 1675 tier_name=tier_name, 1676 bucket_hash=bucket_hash, 1677 recovery_bucket_hash=recovery_hash, 1678 isinstance_item=isinstance_item, 1679 expire_in_orbit_message=expire_in_orbit_message, 1680 expiration_tooltip=expire_tool_tip, 1681 lore_hash=lorehash, 1682 type_and_tier_name=tier_and_name, 1683 summary_hash=summary_hash, 1684 ui_display_style=ui_item_style, 1685 type_name=type_name, 1686 breaker_type_hash=breaker_type_hash, 1687 description=props.description, 1688 display_source=display_source, 1689 hash=props.hash, 1690 damage_types=damage_types, 1691 index=props.index, 1692 icon=props.icon, 1693 has_icon=props.has_icon, 1694 screenshot=screenshot, 1695 watermark_icon=watermark_icon, 1696 watermark_shelved=watermark_shelved, 1697 secondary_icon=secondary_icon, 1698 secondary_overlay=secondary_overlay, 1699 secondary_special=secondary_special, 1700 type=enums.ItemType(int(payload["itemType"])), 1701 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1702 trait_ids=[trait for trait in payload.get("traitIds", [])], 1703 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1704 item_class=enums.Class(int(payload["classType"])), 1705 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1706 breaker_type=int(payload["breakerType"]), 1707 default_damagetype=int(payload["defaultDamageType"]), 1708 default_damagetype_hash=default_damagetype_hash, 1709 damagetype_hashes=damagetype_hashes, 1710 tooltip_notifications=payload["tooltipNotifications"], 1711 not_transferable=payload["nonTransferrable"], 1712 allow_actions=payload["allowActions"], 1713 is_equippable=payload["equippable"], 1714 objects=objects, 1715 background_colors=payload.get("backgroundColor", {}), 1716 season_hash=payload.get("seasonHash"), 1717 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1718 ) 1719 1720 def deserialize_objective_entity( 1721 self, payload: typedefs.JSONObject, / 1722 ) -> entity.ObjectiveEntity: 1723 props = self._set_entity_attrs(payload) 1724 return entity.ObjectiveEntity( 1725 net=self._net, 1726 hash=props.hash, 1727 index=props.index, 1728 description=props.description, 1729 name=props.name, 1730 has_icon=props.has_icon, 1731 icon=props.icon, 1732 unlock_value_hash=payload["unlockValueHash"], 1733 completion_value=payload["completionValue"], 1734 scope=entity.GatingScope(int(payload["scope"])), 1735 location_hash=payload["locationHash"], 1736 allowed_negative_value=payload["allowNegativeValue"], 1737 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1738 counting_downward=payload["isCountingDownward"], 1739 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1740 progress_description=payload["progressDescription"], 1741 perks=payload["perks"], 1742 stats=payload["stats"], 1743 minimum_visibility=payload["minimumVisibilityThreshold"], 1744 allow_over_completion=payload["allowOvercompletion"], 1745 show_value_style=payload["showValueOnComplete"], 1746 display_only_objective=payload["isDisplayOnlyObjective"], 1747 complete_value_style=entity.ValueUIStyle( 1748 int(payload["completedValueStyle"]) 1749 ), 1750 progress_value_style=entity.ValueUIStyle( 1751 int(payload["inProgressValueStyle"]) 1752 ), 1753 ui_label=payload["uiLabel"], 1754 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1755 ) 1756 1757 def _deserialize_activity_values( 1758 self, payload: typedefs.JSONObject, / 1759 ) -> activity.ActivityValues: 1760 team: typing.Optional[int] = None 1761 if raw_team := payload.get("team"): 1762 team = raw_team["basic"]["value"] 1763 return activity.ActivityValues( 1764 assists=payload["assists"]["basic"]["value"], 1765 deaths=payload["deaths"]["basic"]["value"], 1766 kills=payload["kills"]["basic"]["value"], 1767 is_completed=bool(payload["completed"]["basic"]["value"]), 1768 opponents_defeated=payload["opponentsDefeated"]["basic"]["value"], 1769 efficiency=payload["efficiency"]["basic"]["value"], 1770 kd_ratio=payload["killsDeathsRatio"]["basic"]["value"], 1771 kd_assists=payload["killsDeathsAssists"]["basic"]["value"], 1772 score=payload["score"]["basic"]["value"], 1773 duration=payload["activityDurationSeconds"]["basic"]["displayValue"], 1774 team=team, 1775 completion_reason=payload["completionReason"]["basic"]["displayValue"], 1776 fireteam_id=payload["fireteamId"]["basic"]["value"], 1777 start_seconds=payload["startSeconds"]["basic"]["value"], 1778 played_time=payload["timePlayedSeconds"]["basic"]["displayValue"], 1779 player_count=payload["playerCount"]["basic"]["value"], 1780 team_score=payload["teamScore"]["basic"]["value"], 1781 ) 1782 1783 def deserialize_activity( 1784 self, 1785 payload: typedefs.JSONObject, 1786 /, 1787 ) -> activity.Activity: 1788 period = time.clean_date(payload["period"]) 1789 details = payload["activityDetails"] 1790 ref_id = int(details["referenceId"]) 1791 instance_id = int(details["instanceId"]) 1792 mode = enums.GameMode(details["mode"]) 1793 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1794 is_private = details["isPrivate"] 1795 membership_type = enums.MembershipType(int(details["membershipType"])) 1796 1797 # Since we're using the same fields for post activity method 1798 # this check is required since post activity doesn't values values 1799 values = self._deserialize_activity_values(payload["values"]) 1800 1801 return activity.Activity( 1802 net=self._net, 1803 hash=ref_id, 1804 instance_id=instance_id, 1805 mode=mode, 1806 modes=modes, 1807 is_private=is_private, 1808 membership_type=membership_type, 1809 occurred_at=period, 1810 values=values, 1811 ) 1812 1813 def deserialize_activities( 1814 self, payload: typedefs.JSONObject 1815 ) -> iterators.Iterator[activity.Activity]: 1816 return iterators.Iterator( 1817 [ 1818 self.deserialize_activity(activity_) 1819 for activity_ in payload["activities"] 1820 ] 1821 ) 1822 1823 def deserialize_extended_weapon_values( 1824 self, payload: typedefs.JSONObject 1825 ) -> activity.ExtendedWeaponValues: 1826 1827 assists: typing.Optional[int] = None 1828 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1829 assists = raw_assists["basic"]["value"] 1830 assists_damage: typing.Optional[int] = None 1831 1832 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1833 assists_damage = raw_assists_damage["basic"]["value"] 1834 1835 return activity.ExtendedWeaponValues( 1836 reference_id=int(payload["referenceId"]), 1837 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1838 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1839 "value" 1840 ], 1841 assists=assists, 1842 assists_damage=assists_damage, 1843 precision_kills_percentage=( 1844 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1845 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1846 "displayValue" 1847 ], 1848 ), 1849 ) 1850 1851 def _deserialize_extended_values( 1852 self, payload: typedefs.JSONObject 1853 ) -> activity.ExtendedValues: 1854 weapons: typing.Optional[ 1855 collections.Collection[activity.ExtendedWeaponValues] 1856 ] = None 1857 1858 if raw_weapons := payload.get("weapons"): 1859 weapons = [ 1860 self.deserialize_extended_weapon_values(value) for value in raw_weapons 1861 ] 1862 1863 return activity.ExtendedValues( 1864 precision_kills=payload["values"]["precisionKills"]["basic"]["value"], 1865 grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"], 1866 melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"], 1867 super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"], 1868 ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"], 1869 weapons=weapons, 1870 ) 1871 1872 def deserialize_post_activity_player( 1873 self, payload: typedefs.JSONObject, / 1874 ) -> activity.PostActivityPlayer: 1875 player = payload["player"] 1876 1877 class_hash: typedefs.NoneOr[int] = None 1878 if (class_hash := player.get("classHash")) is not None: 1879 class_hash = class_hash 1880 1881 race_hash: typedefs.NoneOr[int] = None 1882 if (race_hash := player.get("raceHash")) is not None: 1883 race_hash = race_hash 1884 1885 gender_hash: typedefs.NoneOr[int] = None 1886 if (gender_hash := player.get("genderHash")) is not None: 1887 gender_hash = gender_hash 1888 1889 character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED 1890 if ( 1891 character_class := player.get("characterClass") 1892 ) and not typedefs.is_unknown(character_class): 1893 character_class = character_class 1894 1895 character_level: typedefs.NoneOr[int] = None 1896 if (character_level := player.get("characterLevel")) is not None: 1897 character_level = character_level 1898 1899 return activity.PostActivityPlayer( 1900 standing=int(payload["standing"]), 1901 score=int(payload["score"]["basic"]["value"]), 1902 character_id=payload["characterId"], 1903 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1904 character_class=character_class, 1905 character_level=character_level, 1906 race_hash=race_hash, 1907 gender_hash=gender_hash, 1908 class_hash=class_hash, 1909 light_level=int(player["lightLevel"]), 1910 emblem_hash=int(player["emblemHash"]), 1911 values=self._deserialize_activity_values(payload["values"]), 1912 extended_values=self._deserialize_extended_values(payload["extended"]), 1913 ) 1914 1915 def _deserialize_post_activity_team( 1916 self, payload: typedefs.JSONObject 1917 ) -> activity.PostActivityTeam: 1918 return activity.PostActivityTeam( 1919 id=payload["teamId"], 1920 is_defeated=bool(payload["standing"]["basic"]["value"]), 1921 score=int(payload["score"]["basic"]["value"]), 1922 name=payload["teamName"], 1923 ) 1924 1925 def deserialize_post_activity( 1926 self, payload: typedefs.JSONObject 1927 ) -> activity.PostActivity: 1928 period = time.clean_date(payload["period"]) 1929 details = payload["activityDetails"] 1930 ref_id = int(details["referenceId"]) 1931 instance_id = int(details["instanceId"]) 1932 mode = enums.GameMode(details["mode"]) 1933 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1934 is_private = details["isPrivate"] 1935 membership_type = enums.MembershipType(int(details["membershipType"])) 1936 return activity.PostActivity( 1937 net=self._net, 1938 hash=ref_id, 1939 membership_type=membership_type, 1940 instance_id=instance_id, 1941 mode=mode, 1942 modes=modes, 1943 is_private=is_private, 1944 occurred_at=period, 1945 starting_phase=int(payload["startingPhaseIndex"]), 1946 players=[ 1947 self.deserialize_post_activity_player(player) 1948 for player in payload["entries"] 1949 ], 1950 teams=[ 1951 self._deserialize_post_activity_team(team) for team in payload["teams"] 1952 ], 1953 ) 1954 1955 def _deserialize_aggregated_activity_values( 1956 self, payload: typedefs.JSONObject 1957 ) -> activity.AggregatedActivityValues: 1958 # This ID is always the same for all aggregated values. 1959 activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"]) 1960 1961 return activity.AggregatedActivityValues( 1962 id=activity_id, 1963 fastest_completion_time=( 1964 int(payload["fastestCompletionMsForActivity"]["basic"]["value"]), 1965 payload["fastestCompletionMsForActivity"]["basic"]["displayValue"], 1966 ), 1967 completions=int(payload["activityCompletions"]["basic"]["value"]), 1968 kills=int(payload["activityKills"]["basic"]["value"]), 1969 deaths=int(payload["activityDeaths"]["basic"]["value"]), 1970 assists=int(payload["activityAssists"]["basic"]["value"]), 1971 seconds_played=( 1972 int(payload["activitySecondsPlayed"]["basic"]["value"]), 1973 payload["activitySecondsPlayed"]["basic"]["displayValue"], 1974 ), 1975 wins=int(payload["activityWins"]["basic"]["value"]), 1976 goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]), 1977 special_actions=int(payload["activitySpecialActions"]["basic"]["value"]), 1978 best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]), 1979 best_single_score=int( 1980 payload["activityBestSingleGameScore"]["basic"]["value"] 1981 ), 1982 goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]), 1983 special_score=int(payload["activitySpecialScore"]["basic"]["value"]), 1984 kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]), 1985 kd_ratio=float( 1986 payload["activityKillsDeathsAssists"]["basic"]["displayValue"] 1987 ), 1988 precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]), 1989 ) 1990 1991 def deserialize_aggregated_activity( 1992 self, payload: typedefs.JSONObject 1993 ) -> activity.AggregatedActivity: 1994 return activity.AggregatedActivity( 1995 hash=int(payload["activityHash"]), 1996 values=self._deserialize_aggregated_activity_values(payload["values"]), 1997 ) 1998 1999 def deserialize_aggregated_activities( 2000 self, payload: typedefs.JSONObject 2001 ) -> iterators.Iterator[activity.AggregatedActivity]: 2002 return iterators.Iterator( 2003 [ 2004 self.deserialize_aggregated_activity(activity) 2005 for activity in payload["activities"] 2006 ] 2007 ) 2008 2009 def deserialize_linked_profiles( 2010 self, payload: typedefs.JSONObject 2011 ) -> profile.LinkedProfile: 2012 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2013 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2014 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2015 2016 if raw_profile := payload.get("profiles"): 2017 for pfile in raw_profile: 2018 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2019 2020 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2021 for raw_error_pfile in raw_profiles_with_errors: 2022 if error_pfile := raw_error_pfile.get("infoCard"): 2023 error_profiles_vec.append( 2024 self.deserialize_destiny_membership(error_pfile) 2025 ) 2026 2027 return profile.LinkedProfile( 2028 net=self._net, 2029 bungie=bungie_user, 2030 profiles=profiles_vec, 2031 profiles_with_errors=error_profiles_vec, 2032 ) 2033 2034 def deserialize_clan_banners( 2035 self, payload: typedefs.JSONObject 2036 ) -> collections.Sequence[clans.ClanBanner]: 2037 banners_seq: typing.MutableSequence[clans.ClanBanner] = [] 2038 if banners := payload.get("clanBannerDecals"): 2039 for k, v in banners.items(): 2040 banner_obj = clans.ClanBanner( 2041 id=int(k), 2042 foreground=assets.Image(v["foregroundPath"]), 2043 background=assets.Image(v["backgroundPath"]), 2044 ) 2045 banners_seq.append(banner_obj) 2046 return banners_seq 2047 2048 def deserialize_public_milestone_content( 2049 self, payload: typedefs.JSONObject 2050 ) -> milestones.MilestoneContent: 2051 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2052 if raw_categories := payload.get("itemCategories"): 2053 for item in raw_categories: 2054 title = undefined.UNDEFINED 2055 if raw_title := item.get("title"): 2056 if raw_title != typedefs.Unknown: 2057 title = raw_title 2058 if raw_hashes := item.get("itemHashes"): 2059 hashes: collections.Sequence[int] = raw_hashes 2060 2061 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2062 2063 about = undefined.UNDEFINED 2064 if (raw_about := payload["about"]) != typedefs.Unknown: 2065 about = raw_about 2066 2067 status = undefined.UNDEFINED 2068 if (raw_status := payload["status"]) != typedefs.Unknown: 2069 status = raw_status 2070 2071 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2072 if raw_tips := payload.get("tips"): 2073 for raw_tip in raw_tips: 2074 if raw_tip == typedefs.Unknown: 2075 raw_tip = undefined.UNDEFINED 2076 tips.append(raw_tip) 2077 2078 return milestones.MilestoneContent( 2079 about=about, status=status, tips=tips, items=items_categoris 2080 ) 2081 2082 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2083 name = undefined.UNDEFINED 2084 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2085 name = raw_name 2086 2087 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2088 2089 if raw_bungie_user := payload.get("bungieNetUser"): 2090 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2091 2092 return friends.Friend( 2093 net=self._net, 2094 id=int(payload["lastSeenAsMembershipId"]), 2095 name=name, 2096 code=payload.get("bungieGlobalDisplayNameCode"), 2097 relationship=enums.Relationship(payload["relationship"]), 2098 user=bungie_user, 2099 online_status=enums.Presence(payload["onlineStatus"]), 2100 online_title=payload["onlineTitle"], 2101 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2102 ) 2103 2104 def deserialize_friends( 2105 self, payload: typedefs.JSONObject 2106 ) -> collections.Sequence[friends.Friend]: 2107 mut_seq: typing.MutableSequence[friends.Friend] = [] 2108 if raw_friends := payload.get("friends"): 2109 for friend in raw_friends: 2110 mut_seq.append(self.deserialize_friend(friend)) 2111 return mut_seq 2112 2113 def deserialize_friend_requests( 2114 self, payload: typedefs.JSONObject 2115 ) -> friends.FriendRequestView: 2116 incoming: typing.MutableSequence[friends.Friend] = [] 2117 outgoing: typing.MutableSequence[friends.Friend] = [] 2118 2119 if raw_incoming_requests := payload.get("incomingRequests"): 2120 for incoming_request in raw_incoming_requests: 2121 incoming.append(self.deserialize_friend(incoming_request)) 2122 2123 if raw_outgoing_requests := payload.get("outgoingRequests"): 2124 for outgoing_request in raw_outgoing_requests: 2125 outgoing.append(self.deserialize_friend(outgoing_request)) 2126 2127 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing) 2128 2129 def _set_fireteam_fields( 2130 self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None 2131 ) -> fireteams.Fireteam: 2132 activity_type = fireteams.FireteamActivity(payload["activityType"]) 2133 return fireteams.Fireteam( 2134 id=int(payload["fireteamId"]), 2135 group_id=int(payload["groupId"]), 2136 platform=fireteams.FireteamPlatform(payload["platform"]), 2137 is_immediate=payload["isImmediate"], 2138 activity_type=activity_type, 2139 owner_id=int(payload["ownerMembershipId"]), 2140 player_slot_count=payload["playerSlotCount"], 2141 available_player_slots=payload["availablePlayerSlotCount"], 2142 available_alternate_slots=payload["availableAlternateSlotCount"], 2143 title=payload["title"], 2144 date_created=time.clean_date(payload["dateCreated"]), 2145 is_public=payload["isPublic"], 2146 locale=fireteams.FireteamLanguage(payload["locale"]), 2147 is_valid=payload["isValid"], 2148 last_modified=time.clean_date(payload["datePlayerModified"]), 2149 total_results=total_results or 0, 2150 ) 2151 2152 def deserialize_fireteams( 2153 self, payload: typedefs.JSONObject 2154 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2155 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2156 2157 result: list[typedefs.JSONObject] 2158 if not (result := payload["results"]): 2159 return None 2160 for elem in result: 2161 fireteams_.append( 2162 self._set_fireteam_fields( 2163 elem, total_results=int(payload["totalResults"]) 2164 ) 2165 ) 2166 return fireteams_ 2167 2168 def deserialize_fireteam_destiny_users( 2169 self, payload: typedefs.JSONObject 2170 ) -> fireteams.FireteamUser: 2171 destiny_obj = self.deserialize_destiny_membership(payload) 2172 # We could helpers.just return a DestinyMembership object but this is 2173 # missing the fireteam display name and id fields. 2174 return fireteams.FireteamUser( 2175 net=self._net, 2176 id=destiny_obj.id, 2177 code=destiny_obj.code, 2178 icon=destiny_obj.icon, 2179 types=destiny_obj.types, 2180 type=destiny_obj.type, 2181 is_public=destiny_obj.is_public, 2182 crossave_override=destiny_obj.crossave_override, 2183 name=destiny_obj.name, 2184 last_seen_name=destiny_obj.last_seen_name, 2185 fireteam_display_name=payload["FireteamDisplayName"], 2186 fireteam_membership_id=enums.MembershipType( 2187 payload["FireteamMembershipType"] 2188 ), 2189 ) 2190 2191 def deserialize_fireteam_members( 2192 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2193 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2194 members_: list[fireteams.FireteamMember] = [] 2195 if members := payload.get("Members" if not alternatives else "Alternates"): 2196 for member in members: 2197 bungie_fields = self.deserialize_partial_bungie_user(member) 2198 members_fields = fireteams.FireteamMember( 2199 destiny_user=self.deserialize_fireteam_destiny_users(member), 2200 has_microphone=member["hasMicrophone"], 2201 character_id=int(member["characterId"]), 2202 date_joined=time.clean_date(member["dateJoined"]), 2203 last_platform_invite_date=time.clean_date( 2204 member["lastPlatformInviteAttemptDate"] 2205 ), 2206 last_platform_invite_result=int( 2207 member["lastPlatformInviteAttemptResult"] 2208 ), 2209 net=self._net, 2210 name=bungie_fields.name, 2211 id=bungie_fields.id, 2212 icon=bungie_fields.icon, 2213 is_public=bungie_fields.is_public, 2214 crossave_override=bungie_fields.crossave_override, 2215 types=bungie_fields.types, 2216 type=bungie_fields.type, 2217 ) 2218 members_.append(members_fields) 2219 else: 2220 return None 2221 return members_ 2222 2223 def deserialize_available_fireteams( 2224 self, 2225 data: typedefs.JSONObject, 2226 *, 2227 no_results: bool = False, 2228 ) -> typing.Union[ 2229 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2230 ]: 2231 fireteams_: list[fireteams.AvailableFireteam] = [] 2232 2233 # This needs to be used outside the results 2234 # JSON key. 2235 if no_results is True: 2236 payload = data 2237 2238 if result := payload.get("results"): 2239 2240 for fireteam in result: 2241 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2242 fireteams_fields = fireteams.AvailableFireteam( 2243 id=found_fireteams.id, 2244 group_id=found_fireteams.group_id, 2245 platform=found_fireteams.platform, 2246 activity_type=found_fireteams.activity_type, 2247 is_immediate=found_fireteams.is_immediate, 2248 is_public=found_fireteams.is_public, 2249 is_valid=found_fireteams.is_valid, 2250 owner_id=found_fireteams.owner_id, 2251 player_slot_count=found_fireteams.player_slot_count, 2252 available_player_slots=found_fireteams.available_player_slots, 2253 available_alternate_slots=found_fireteams.available_alternate_slots, 2254 title=found_fireteams.title, 2255 date_created=found_fireteams.date_created, 2256 locale=found_fireteams.locale, 2257 last_modified=found_fireteams.last_modified, 2258 total_results=found_fireteams.total_results, 2259 members=self.deserialize_fireteam_members(payload), 2260 alternatives=self.deserialize_fireteam_members( 2261 payload, alternatives=True 2262 ), 2263 ) 2264 fireteams_.append(fireteams_fields) 2265 if no_results: 2266 return fireteams_fields 2267 return fireteams_ 2268 2269 def deserialize_fireteam_party( 2270 self, payload: typedefs.JSONObject 2271 ) -> fireteams.FireteamParty: 2272 last_destination_hash: typing.Optional[int] = None 2273 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2274 last_destination_hash = int(raw_dest_hash) 2275 2276 return fireteams.FireteamParty( 2277 members=[ 2278 self._deserialize_fireteam_party_member(member) 2279 for member in payload["partyMembers"] 2280 ], 2281 activity=self._deserialize_fireteam_party_current_activity( 2282 payload["currentActivity"] 2283 ), 2284 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2285 last_destination_hash=last_destination_hash, 2286 tracking=payload["tracking"], 2287 ) 2288 2289 def _deserialize_fireteam_party_member( 2290 self, payload: typedefs.JSONObject 2291 ) -> fireteams.FireteamPartyMember: 2292 2293 status = fireteams.FireteamPartyMemberState(payload["status"]) 2294 displayname: undefined.UndefinedOr[str] = undefined.UNDEFINED 2295 if raw_name := payload.get("displayName"): 2296 displayname = raw_name 2297 2298 return fireteams.FireteamPartyMember( 2299 membership_id=int(payload["membershipId"]), 2300 emblem_hash=int(payload["emblemHash"]), 2301 status=status, 2302 display_name=displayname, 2303 ) 2304 2305 def _deserialize_fireteam_party_current_activity( 2306 self, payload: typedefs.JSONObject 2307 ) -> fireteams.FireteamPartyCurrentActivity: 2308 start_date: typing.Optional[datetime.datetime] = None 2309 if raw_start_date := payload.get("startTime"): 2310 start_date = time.clean_date(raw_start_date) 2311 2312 end_date: typing.Optional[datetime.datetime] = None 2313 if raw_end_date := payload.get("endTime"): 2314 end_date = time.clean_date(raw_end_date) 2315 return fireteams.FireteamPartyCurrentActivity( 2316 start_time=start_date, 2317 end_time=end_date, 2318 score=float(payload["score"]), 2319 highest_opposing_score=float(payload["highestOpposingFactionScore"]), 2320 opponenst_count=int(payload["numberOfOpponents"]), 2321 player_count=int(payload["numberOfPlayers"]), 2322 ) 2323 2324 def _deserialize_fireteam_party_settings( 2325 self, payload: typedefs.JSONObject 2326 ) -> fireteams.FireteamPartySettings: 2327 closed_reasons = enums.ClosedReasons(payload["closedReasons"]) 2328 return fireteams.FireteamPartySettings( 2329 open_slots=int(payload["openSlots"]), 2330 privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])), 2331 closed_reasons=closed_reasons, 2332 ) 2333 2334 def deserialize_seasonal_artifact( 2335 self, payload: typedefs.JSONObject 2336 ) -> season.Artifact: 2337 if raw_artifact := payload.get("seasonalArtifact"): 2338 if points := raw_artifact.get("pointProgression"): 2339 points_prog = progressions.Progression( 2340 hash=points["progressionHash"], 2341 level=points["level"], 2342 cap=points["levelCap"], 2343 daily_limit=points["dailyLimit"], 2344 weekly_limit=points["weeklyLimit"], 2345 current_progress=points["currentProgress"], 2346 daily_progress=points["dailyProgress"], 2347 needed=points["progressToNextLevel"], 2348 next_level=points["nextLevelAt"], 2349 ) 2350 2351 if bonus := raw_artifact.get("powerBonusProgression"): 2352 power_bonus_prog = progressions.Progression( 2353 hash=bonus["progressionHash"], 2354 level=bonus["level"], 2355 cap=bonus["levelCap"], 2356 daily_limit=bonus["dailyLimit"], 2357 weekly_limit=bonus["weeklyLimit"], 2358 current_progress=bonus["currentProgress"], 2359 daily_progress=bonus["dailyProgress"], 2360 needed=bonus["progressToNextLevel"], 2361 next_level=bonus["nextLevelAt"], 2362 ) 2363 artifact = season.Artifact( 2364 net=self._net, 2365 hash=raw_artifact["artifactHash"], 2366 power_bonus=raw_artifact["powerBonus"], 2367 acquired_points=raw_artifact["pointsAcquired"], 2368 bonus=power_bonus_prog, 2369 points=points_prog, 2370 ) 2371 return artifact 2372 2373 def deserialize_profile_progression( 2374 self, payload: typedefs.JSONObject 2375 ) -> profile.ProfileProgression: 2376 return profile.ProfileProgression( 2377 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2378 checklist={ 2379 int(check_id): checklists 2380 for check_id, checklists in payload["data"]["checklists"].items() 2381 }, 2382 ) 2383 2384 def deserialize_instanced_item( 2385 self, payload: typedefs.JSONObject 2386 ) -> items.ItemInstance: 2387 damage_type_hash: typing.Optional[int] = None 2388 if raw_damagetype_hash := payload.get("damageTypeHash"): 2389 damage_type_hash = int(raw_damagetype_hash) 2390 2391 required_hashes: typing.Optional[collections.Collection[int]] = None 2392 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2393 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2394 2395 breaker_type: typing.Optional[items.ItemBreakerType] = None 2396 if raw_break_type := payload.get("breakerType"): 2397 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2398 2399 breaker_type_hash: typing.Optional[int] = None 2400 if raw_break_type_hash := payload.get("breakerTypeHash"): 2401 breaker_type_hash = int(raw_break_type_hash) 2402 2403 energy: typing.Optional[items.ItemEnergy] = None 2404 if raw_energy := payload.get("energy"): 2405 energy = self.deserialize_item_energy(raw_energy) 2406 2407 primary_stats = None 2408 if raw_primary_stats := payload.get("primaryStat"): 2409 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2410 2411 return items.ItemInstance( 2412 damage_type=enums.DamageType(int(payload["damageType"])), 2413 damage_type_hash=damage_type_hash, 2414 primary_stat=primary_stats, 2415 item_level=int(payload["itemLevel"]), 2416 quality=int(payload["quality"]), 2417 is_equipped=payload["isEquipped"], 2418 can_equip=payload["canEquip"], 2419 equip_required_level=int(payload["equipRequiredLevel"]), 2420 required_equip_unlock_hashes=required_hashes, 2421 cant_equip_reason=int(payload["cannotEquipReason"]), 2422 breaker_type=breaker_type, 2423 breaker_type_hash=breaker_type_hash, 2424 energy=energy, 2425 ) 2426 2427 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2428 energy_hash: typing.Optional[int] = None 2429 if raw_energy_hash := payload.get("energyTypeHash"): 2430 energy_hash = int(raw_energy_hash) 2431 2432 return items.ItemEnergy( 2433 hash=energy_hash, 2434 type=items.ItemEnergyType(int(payload["energyType"])), 2435 capacity=int(payload["energyCapacity"]), 2436 used_energy=int(payload["energyUsed"]), 2437 unused_energy=int(payload["energyUnused"]), 2438 ) 2439 2440 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2441 perk_hash: typing.Optional[int] = None 2442 if raw_perk_hash := payload.get("perkHash"): 2443 perk_hash = int(raw_perk_hash) 2444 2445 return items.ItemPerk( 2446 hash=perk_hash, 2447 icon=assets.Image(payload["iconPath"]), 2448 is_active=payload["isActive"], 2449 is_visible=payload["visible"], 2450 ) 2451 2452 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2453 plug_hash: typing.Optional[int] = None 2454 if raw_plug_hash := payload.get("plugHash"): 2455 plug_hash = int(raw_plug_hash) 2456 2457 enable_fail_indexes: typing.Optional[list[int]] = None 2458 if raw_indexes := payload.get("enableFailIndexes"): 2459 enable_fail_indexes = [int(index) for index in raw_indexes] 2460 2461 return items.ItemSocket( 2462 plug_hash=plug_hash, 2463 is_enabled=payload["isEnabled"], 2464 enable_fail_indexes=enable_fail_indexes, 2465 is_visible=payload.get("visible"), 2466 ) 2467 2468 def deserialize_item_stats_view( 2469 self, payload: typedefs.JSONObject 2470 ) -> items.ItemStatsView: 2471 return items.ItemStatsView( 2472 stat_hash=payload.get("statHash"), value=payload.get("value") 2473 ) 2474 2475 def deserialize_plug_item_state( 2476 self, payload: typedefs.JSONObject 2477 ) -> items.PlugItemState: 2478 item_hash: typing.Optional[int] = None 2479 if raw_item_hash := payload.get("plugItemHash"): 2480 item_hash = int(raw_item_hash) 2481 2482 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2483 if raw_fail_indexes := payload.get("insertFailIndexes"): 2484 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2485 2486 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2487 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2488 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2489 2490 return items.PlugItemState( 2491 item_hash=item_hash, 2492 insert_fail_indexes=insert_fail_indexes, 2493 enable_fail_indexes=enable_fail_indexes, 2494 is_enabled=payload["enabled"], 2495 can_insert=payload["canInsert"], 2496 )
The base deserialization factory class for all aiobungie objects.
Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
into a aiobungie.crates Python classes.
73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 )
Deserialize a raw JSON Bungie.net user only payload into a user object.
This only returns the Bungie.net user and not the Destiny memberships.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.BungieUser: A Bungie user.
97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.UNDEFINED), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 )
Deserialize a raw JSON of a partial bungieNetUserInfo.
A partial user is a bungie.net user payload with missing information from
the main BungieUser object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PartialBungieUser: A partial bungie user.
114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 )
Deserialize a raw JSON of destinyUserInfo destiny membership information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data]
Deserialize a raw JSON payload/array of destinyUserInfo.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 148 primary_membership_id: typing.Optional[int] = None 149 if raw_primary_id := data.get("primaryMembershipId"): 150 primary_membership_id = int(raw_primary_id) 151 152 return user.User( 153 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 154 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 155 primary_membership_id=primary_membership_id, 156 )
Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.User: A user object.
158 def deserialize_searched_user( 159 self, payload: typedefs.JSONObject 160 ) -> user.SearchableDestinyUser: 161 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 162 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 163 raw_name 164 ): 165 name = raw_name 166 167 code: typing.Optional[int] = None 168 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 169 code = int(raw_code) 170 171 bungie_id: typing.Optional[int] = None 172 if raw_bungie_id := payload.get("bungieNetMembershipId"): 173 bungie_id = int(raw_bungie_id) 174 175 return user.SearchableDestinyUser( 176 name=name, 177 code=code, 178 bungie_id=bungie_id, 179 memberships=self.deserialize_destiny_memberships( 180 payload["destinyMemberships"] 181 ), 182 )
Deserialize the results of user search details.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.SearchableDestinyUser: The searched for Destiny 2 membership.
184 def deserialize_user_credentials( 185 self, payload: typedefs.JSONArray 186 ) -> collections.Sequence[user.UserCredentials]: 187 return [ 188 user.UserCredentials( 189 type=enums.CredentialType(int(creds["credentialType"])), 190 display_name=creds["credentialDisplayName"], 191 is_public=creds["isPublic"], 192 self_as_string=creds.get("credentialAsString", undefined.UNDEFINED), 193 ) 194 for creds in payload 195 ]
Deserialize a JSON array of Bungie user credentials.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of user's credentials.
197 def deserialize_user_themes( 198 self, payload: typedefs.JSONArray 199 ) -> collections.Sequence[user.UserThemes]: 200 return [ 201 user.UserThemes( 202 id=int(entry["userThemeId"]), 203 name=entry["userThemeName"] 204 if "userThemeName" in entry 205 else undefined.UNDEFINED, 206 description=entry["userThemeDescription"] 207 if "userThemeDescription" in entry 208 else undefined.UNDEFINED, 209 ) 210 for entry in payload 211 ]
Deserialize a raw JSON array of Bungie user themes.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
213 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 214 215 # This is kinda redundant 216 data = payload 217 218 # This is always outside the details. 219 current_user_map: typing.Optional[ 220 collections.Mapping[str, clans.ClanMember] 221 ] = None 222 if raw_current_user_map := payload.get("currentUserMemberMap"): 223 current_user_map = { 224 membership_type: self.deserialize_clan_member(membership) 225 for membership_type, membership in raw_current_user_map.items() 226 } 227 228 try: 229 data = payload["detail"] 230 except KeyError: 231 pass 232 233 id = data["groupId"] 234 name = data["name"] 235 created_at = data["creationDate"] 236 member_count = data["memberCount"] 237 about = data["about"] 238 motto = data["motto"] 239 is_public = data["isPublic"] 240 banner = assets.Image(str(data["bannerPath"])) 241 avatar = assets.Image(str(data["avatarPath"])) 242 tags = data["tags"] 243 type = data["groupType"] 244 245 features = data["features"] 246 features_obj = clans.ClanFeatures( 247 max_members=features["maximumMembers"], 248 max_membership_types=features["maximumMembershipsOfGroupType"], 249 capabilities=features["capabilities"], 250 membership_types=features["membershipTypes"], 251 invite_permissions=features["invitePermissionOverride"], 252 update_banner_permissions=features["updateBannerPermissionOverride"], 253 update_culture_permissions=features["updateCulturePermissionOverride"], 254 join_level=features["joinLevel"], 255 ) 256 257 information: typedefs.JSONObject = data["clanInfo"] 258 progression: collections.Mapping[int, progressions.Progression] = { 259 int(prog_hash): self.deserialize_progressions(prog) 260 for prog_hash, prog in information["d2ClanProgressions"].items() 261 } 262 263 founder: typedefs.NoneOr[clans.ClanMember] = None 264 if raw_founder := payload.get("founder"): 265 founder = self.deserialize_clan_member(raw_founder) 266 267 return clans.Clan( 268 net=self._net, 269 id=int(id), 270 name=name, 271 type=enums.GroupType(type), 272 created_at=time.clean_date(created_at), 273 member_count=member_count, 274 motto=motto, 275 about=about, 276 is_public=is_public, 277 banner=banner, 278 avatar=avatar, 279 tags=tags, 280 features=features_obj, 281 owner=founder, 282 progressions=progression, 283 call_sign=information["clanCallsign"], 284 banner_data=information["clanBannerData"], 285 chat_security=data["chatSecurity"], 286 conversation_id=int(data["conversationId"]), 287 allow_chat=data["allowChat"], 288 theme=data["theme"], 289 current_user_membership=current_user_map, 290 )
Deserialize a raw JSON payload of Bungie clan information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Clan: A clan owner.
292 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 293 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 294 return clans.ClanMember( 295 net=self._net, 296 last_seen_name=destiny_user.last_seen_name, 297 id=destiny_user.id, 298 name=destiny_user.name, 299 icon=destiny_user.icon, 300 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 301 group_id=int(data["groupId"]), 302 joined_at=time.clean_date(data["joinDate"]), 303 types=destiny_user.types, 304 is_public=destiny_user.is_public, 305 type=destiny_user.type, 306 code=destiny_user.code, 307 is_online=data["isOnline"], 308 crossave_override=destiny_user.crossave_override, 309 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 310 if "bungieNetUserInfo" in data 311 else None, 312 member_type=enums.ClanMemberType(int(data["memberType"])), 313 )
Deserialize a JSON payload of a clan member information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ClanMember: A clan member.
315 def deserialize_clan_members( 316 self, data: typedefs.JSONObject, / 317 ) -> iterators.Iterator[clans.ClanMember]: 318 return iterators.Iterator( 319 [self.deserialize_clan_member(member) for member in data["results"]] 320 )
Deserialize a JSON payload of a clan members information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]: An iterator of clan members of the deserialized payload.
322 def deserialize_group_member( 323 self, payload: typedefs.JSONObject 324 ) -> clans.GroupMember: 325 member = payload["member"] 326 return clans.GroupMember( 327 net=self._net, 328 join_date=time.clean_date(member["joinDate"]), 329 group_id=int(member["groupId"]), 330 member_type=enums.ClanMemberType(member["memberType"]), 331 is_online=member["isOnline"], 332 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 333 inactive_memberships=payload.get("areAllMembershipsInactive", None), 334 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 335 group=self.deserialize_clan(payload["group"]), 336 )
Deserialize a JSON payload of group information for a member.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.typedefs.NoneOr[aiobungie.crates.GroupMember]: A group member. This can returnNoneif nothing was found.
354 def deserialize_clan_conversations( 355 self, payload: typedefs.JSONArray 356 ) -> collections.Sequence[clans.ClanConversation]: 357 return [self._deserialize_clan_conversation(conv) for conv in payload]
Deserialize a JSON array of a clan conversations information.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of clan conversations of the deserialized payload.
359 def deserialize_app_owner( 360 self, payload: typedefs.JSONObject 361 ) -> application.ApplicationOwner: 362 return application.ApplicationOwner( 363 net=self._net, 364 name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED), 365 id=int(payload["membershipId"]), 366 type=enums.MembershipType(payload["membershipType"]), 367 icon=assets.Image(str(payload["iconPath"])), 368 is_public=payload["isPublic"], 369 code=payload.get("bungieGlobalDisplayNameCode", None), 370 )
Deserialize a JSON payload of Bungie Developer portal application owner information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.ApplicationOwner: An application owner.
372 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 373 return application.Application( 374 id=int(payload["applicationId"]), 375 name=payload["name"], 376 link=payload["link"], 377 status=payload["status"], 378 redirect_url=payload.get("redirectUrl", None), 379 created_at=time.clean_date(str(payload["creationDate"])), 380 published_at=time.clean_date(str(payload["firstPublished"])), 381 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 382 scope=payload.get("scope", undefined.UNDEFINED), 383 )
Deserialize a JSON payload of Bungie Developer portal application information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.Application: An application.
406 def deserialize_profile( 407 self, payload: typedefs.JSONObject, / 408 ) -> typing.Optional[profile.Profile]: 409 if (raw_profile := payload.get("data")) is None: 410 return None 411 412 payload = raw_profile 413 id = int(payload["userInfo"]["membershipId"]) 414 name = payload["userInfo"]["displayName"] 415 is_public = payload["userInfo"]["isPublic"] 416 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 417 last_played = time.clean_date(str(payload["dateLastPlayed"])) 418 character_ids = [int(cid) for cid in payload["characterIds"]] 419 power_cap = payload["currentSeasonRewardPowerCap"] 420 421 return profile.Profile( 422 id=int(id), 423 name=name, 424 is_public=is_public, 425 type=type, 426 last_played=last_played, 427 character_ids=character_ids, 428 power_cap=power_cap, 429 net=self._net, 430 )
Deserialize a JSON payload of Bungie.net profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[aiobungie.crates.Profile]: A profile.
432 def deserialize_profile_item( 433 self, payload: typedefs.JSONObject 434 ) -> profile.ProfileItemImpl: 435 436 instance_id: typing.Optional[int] = None 437 if raw_instance_id := payload.get("itemInstanceId"): 438 instance_id = int(raw_instance_id) 439 440 version_number: typing.Optional[int] = None 441 if raw_version := payload.get("versionNumber"): 442 version_number = int(raw_version) 443 444 transfer_status = enums.TransferStatus(payload["transferStatus"]) 445 446 return profile.ProfileItemImpl( 447 net=self._net, 448 hash=payload["itemHash"], 449 quantity=payload["quantity"], 450 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 451 location=enums.ItemLocation(payload["location"]), 452 bucket=payload["bucketHash"], 453 transfer_status=transfer_status, 454 lockable=payload["lockable"], 455 state=enums.ItemState(payload["state"]), 456 dismantel_permissions=payload["dismantlePermission"], 457 is_wrapper=payload["isWrapper"], 458 instance_id=instance_id, 459 version_number=version_number, 460 ornament_id=payload.get("overrideStyleItemHash"), 461 )
Deserialize a JSON payload of a singular profile component item.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ProfileItemImpl: Implementation of a Destiny 2 profile component item.
463 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 464 return records.Objective( 465 net=self._net, 466 hash=payload["objectiveHash"], 467 visible=payload["visible"], 468 complete=payload["complete"], 469 completion_value=payload["completionValue"], 470 progress=payload.get("progress"), 471 destination_hash=payload.get("destinationHash"), 472 activity_hash=payload.get("activityHash"), 473 )
Deserialize a JSON payload of an objective found in a record profile component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.records.Objective: A record objective object.
475 def deserialize_records( 476 self, 477 payload: typedefs.JSONObject, 478 scores: typing.Optional[records.RecordScores] = None, 479 **nodes: int, 480 ) -> records.Record: 481 objectives: typing.Optional[list[records.Objective]] = None 482 interval_objectives: typing.Optional[list[records.Objective]] = None 483 record_state: typedefs.IntAnd[records.RecordState] 484 485 record_state = records.RecordState(payload["state"]) 486 487 if raw_objs := payload.get("objectives"): 488 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 489 490 if raw_interval_objs := payload.get("intervalObjectives"): 491 interval_objectives = [ 492 self.deserialize_objectives(obj) for obj in raw_interval_objs 493 ] 494 495 return records.Record( 496 scores=scores, 497 categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED), 498 seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED), 499 state=record_state, 500 objectives=objectives, 501 interval_objectives=interval_objectives, 502 redeemed_count=payload.get("intervalsRedeemedCount", 0), 503 completion_times=payload.get("completedCount", None), 504 reward_visibility=payload.get("rewardVisibilty", None), 505 )
Deserialize a JSON object of a profile record component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload - scores (
typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature ofaiobungie.crates.CharacterRecordwith the record object. As it will always beNonein that object. - **nodes (
int): An int kwargs use to grab the node hashes while deserializing components.
Returns
aiobungie.records.Record: A standard implementation of a profile record component.
507 def deserialize_character_records( 508 self, 509 payload: typedefs.JSONObject, 510 scores: typing.Optional[records.RecordScores] = None, 511 record_hashes: typing.Optional[list[int]] = None, 512 ) -> records.CharacterRecord: 513 514 record = self.deserialize_records(payload, scores) 515 return records.CharacterRecord( 516 scores=scores, 517 categories_node_hash=record.categories_node_hash, 518 seals_node_hash=record.seals_node_hash, 519 state=record.state, 520 objectives=record.objectives, 521 interval_objectives=record.interval_objectives, 522 redeemed_count=payload.get("intervalsRedeemedCount", 0), 523 completion_times=payload.get("completedCount"), 524 reward_visibility=payload.get("rewardVisibilty"), 525 record_hashes=record_hashes or [], 526 )
Deserialize a JSON object of a profile character record component.
This almost does the same this as deserialize_records but
has more fields which can only be found in a character record.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
528 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 529 return character.Dye( 530 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 531 )
Deserialize a JSON payload of a character's dye information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.Dye: Information about a character dye object.
533 def deserialize_character_customization( 534 self, payload: typedefs.JSONObject 535 ) -> character.CustomizationOptions: 536 return character.CustomizationOptions( 537 personality=payload["personality"], 538 face=payload["face"], 539 skin_color=payload["skinColor"], 540 lip_color=payload["lipColor"], 541 eye_color=payload["eyeColor"], 542 hair_colors=payload.get("hairColors", []), 543 feature_colors=payload.get("featureColors", []), 544 decal_color=payload["decalColor"], 545 wear_helmet=payload["wearHelmet"], 546 hair_index=payload["hairIndex"], 547 feature_index=payload["featureIndex"], 548 decal_index=payload["decalIndex"], 549 )
Deserialize a JSON payload of a character customization information found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
551 def deserialize_character_minimal_equipments( 552 self, payload: typedefs.JSONObject 553 ) -> character.MinimalEquipments: 554 dyes = None 555 if raw_dyes := payload.get("dyes"): 556 if raw_dyes: 557 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 558 return character.MinimalEquipments( 559 net=self._net, item_hash=payload["itemHash"], dyes=dyes 560 )
Deserialize a singular JSON peer view of equipment found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
562 def deserialize_character_render_data( 563 self, payload: typedefs.JSONObject, / 564 ) -> character.RenderedData: 565 return character.RenderedData( 566 net=self._net, 567 customization=self.deserialize_character_customization( 568 payload["customization"] 569 ), 570 custom_dyes=[ 571 self.deserialize_character_dye(dye) 572 for dye in payload["customDyes"] 573 if dye 574 ], 575 equipment=[ 576 self.deserialize_character_minimal_equipments(equipment) 577 for equipment in payload["peerView"]["equipment"] 578 ], 579 )
Deserialize a JSON payload of a profile character render data component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.RenderedData: A character rendered data profile component.
581 def deserialize_available_activity( 582 self, payload: typedefs.JSONObject 583 ) -> activity.AvailableActivity: 584 return activity.AvailableActivity( 585 hash=payload["activityHash"], 586 is_new=payload["isNew"], 587 is_completed=payload["isCompleted"], 588 is_visible=payload["isVisible"], 589 display_level=payload.get("displayLevel"), 590 recommended_light=payload.get("recommendedLight"), 591 difficulty=activity.Difficulty(payload["difficultyTier"]), 592 can_join=payload["canJoin"], 593 can_lead=payload["canLead"], 594 )
Deserialize a JSON payload of an available activities.
This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AvailableActivity: An available activity object.
596 def deserialize_character_activity( 597 self, payload: typedefs.JSONObject 598 ) -> activity.CharacterActivity: 599 current_mode: typing.Optional[enums.GameMode] = None 600 if raw_current_mode := payload.get("currentActivityModeType"): 601 current_mode = enums.GameMode(raw_current_mode) 602 603 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 604 if raw_current_modes := payload.get("currentActivityModeTypes"): 605 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 606 607 return activity.CharacterActivity( 608 date_started=time.clean_date(payload["dateActivityStarted"]), 609 current_hash=payload["currentActivityHash"], 610 current_mode_hash=payload["currentActivityModeHash"], 611 current_mode=current_mode, 612 current_mode_hashes=payload.get("currentActivityModeHashes"), 613 current_mode_types=current_mode_types, 614 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 615 last_story_hash=payload["lastCompletedStoryHash"], 616 available_activities=[ 617 self.deserialize_available_activity(activity_) 618 for activity_ in payload["availableActivities"] 619 ], 620 )
Deserialize a JSON payload of character activity profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterActivity: A character activities component object.
622 def deserialize_profile_items( 623 self, payload: typedefs.JSONObject, / 624 ) -> list[profile.ProfileItemImpl]: 625 return [self.deserialize_profile_item(item) for item in payload["items"]]
Deserialize a JSON payload of profile items component information.
This may deserialize profileInventories or profileCurrencies or any
other alternatives.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.ProfileItemImpl]]: A profile component object that contains items of the deserialized payload.
668 def deserialize_progressions( 669 self, payload: typedefs.JSONObject 670 ) -> progressions.Progression: 671 return progressions.Progression( 672 hash=int(payload["progressionHash"]), 673 level=int(payload["level"]), 674 cap=int(payload["levelCap"]), 675 daily_limit=int(payload["dailyLimit"]), 676 weekly_limit=int(payload["weeklyLimit"]), 677 current_progress=int(payload["currentProgress"]), 678 daily_progress=int(payload["dailyProgress"]), 679 needed=int(payload["progressToNextLevel"]), 680 next_level=int(payload["nextLevelAt"]), 681 )
769 def deserialize_milestone( 770 self, payload: typedefs.JSONObject 771 ) -> milestones.Milestone: 772 start_date: typing.Optional[datetime.datetime] = None 773 if raw_start_date := payload.get("startDate"): 774 start_date = time.clean_date(raw_start_date) 775 776 end_date: typing.Optional[datetime.datetime] = None 777 if raw_end_date := payload.get("endDate"): 778 end_date = time.clean_date(raw_end_date) 779 780 rewards: typing.Optional[ 781 collections.Collection[milestones.MilestoneReward] 782 ] = None 783 if raw_rewards := payload.get("rewards"): 784 rewards = [ 785 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 786 ] 787 788 activities: typing.Optional[ 789 collections.Sequence[milestones.MilestoneActivity] 790 ] = None 791 if raw_activities := payload.get("activities"): 792 activities = [ 793 self._deserialize_milestone_activity(active) 794 for active in raw_activities 795 ] 796 797 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 798 if raw_quests := payload.get("availableQuests"): 799 quests = [ 800 self._deserialize_milestone_available_quest(quest) 801 for quest in raw_quests 802 ] 803 804 vendors: typing.Optional[ 805 collections.Sequence[milestones.MilestoneVendor] 806 ] = None 807 if raw_vendors := payload.get("vendors"): 808 vendors = [ 809 milestones.MilestoneVendor( 810 vendor_hash=vendor["vendorHash"], 811 preview_itemhash=vendor.get("previewItemHash"), 812 ) 813 for vendor in raw_vendors 814 ] 815 816 return milestones.Milestone( 817 hash=payload["milestoneHash"], 818 start_date=start_date, 819 end_date=end_date, 820 order=payload["order"], 821 rewards=rewards, 822 available_quests=quests, 823 activities=activities, 824 vendors=vendors, 825 )
879 def deserialize_character_progressions( 880 self, payload: typedefs.JSONObject 881 ) -> character.CharacterProgression: 882 progressions_ = { 883 int(prog_id): self.deserialize_progressions(prog) 884 for prog_id, prog in payload["progressions"].items() 885 } 886 887 factions = { 888 int(faction_id): self._deserialize_factions(faction) 889 for faction_id, faction in payload["factions"].items() 890 } 891 892 milestones_ = { 893 int(milestone_hash): self.deserialize_milestone(milestone) 894 for milestone_hash, milestone in payload["milestones"].items() 895 } 896 897 uninstanced_item_objectives = { 898 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 899 for item_hash, obj in payload["uninstancedItemObjectives"].items() 900 } 901 902 artifact = payload["seasonalArtifact"] 903 seasonal_artifact = season.CharacterScopedArtifact( 904 hash=artifact["artifactHash"], 905 points_used=artifact["pointsUsed"], 906 reset_count=artifact["resetCount"], 907 tiers=[ 908 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 909 ], 910 ) 911 checklists = payload["checklists"] 912 913 return character.CharacterProgression( 914 progressions=progressions_, 915 factions=factions, 916 checklists=checklists, 917 milestones=milestones_, 918 seasonal_artifact=seasonal_artifact, 919 uninstanced_item_objectives=uninstanced_item_objectives, 920 )
922 def deserialize_character_progressions_mapping( 923 self, payload: typedefs.JSONObject 924 ) -> collections.Mapping[int, character.CharacterProgression]: 925 character_progressions: collections.Mapping[ 926 int, character.CharacterProgression 927 ] = {} 928 for char_id, data in payload["data"].items(): 929 # A little hack to stop mypy complaining about Mapping <-> dict 930 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 931 return character_progressions
933 def deserialize_characters_records( 934 self, 935 payload: typedefs.JSONObject, 936 ) -> collections.Mapping[int, records.CharacterRecord]: 937 938 return { 939 int(rec_id): self.deserialize_character_records( 940 rec, record_hashes=payload.get("featuredRecordHashes") 941 ) 942 for rec_id, rec in payload["records"].items() 943 }
945 def deserialize_profile_records( 946 self, payload: typedefs.JSONObject 947 ) -> collections.Mapping[int, records.Record]: 948 raw_profile_records = payload["data"] 949 scores = records.RecordScores( 950 current_score=raw_profile_records["score"], 951 legacy_score=raw_profile_records["legacyScore"], 952 lifetime_score=raw_profile_records["lifetimeScore"], 953 ) 954 return { 955 int(record_id): self.deserialize_records( 956 record, 957 scores, 958 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 959 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 960 ) 961 for record_id, record in raw_profile_records["records"].items() 962 }
999 def deserialize_craftables_component( 1000 self, payload: typedefs.JSONObject 1001 ) -> components.CraftablesComponent: 1002 return components.CraftablesComponent( 1003 net=self._net, 1004 craftables={ 1005 int(item_id): self._deserialize_craftable_item(item) 1006 for item_id, item in payload["craftables"].items() 1007 if item is not None 1008 }, 1009 crafting_root_node_hash=payload["craftingRootNodeHash"], 1010 )
1012 def deserialize_components( # noqa: C901 Too complex. 1013 self, payload: typedefs.JSONObject 1014 ) -> components.Component: 1015 1016 profile_: typing.Optional[profile.Profile] = None 1017 if raw_profile := payload.get("profile"): 1018 profile_ = self.deserialize_profile(raw_profile) 1019 1020 profile_progression: typing.Optional[profile.ProfileProgression] = None 1021 if raw_profile_progression := payload.get("profileProgression"): 1022 profile_progression = self.deserialize_profile_progression( 1023 raw_profile_progression 1024 ) 1025 1026 profile_currencies: typing.Optional[ 1027 collections.Sequence[profile.ProfileItemImpl] 1028 ] = None 1029 if raw_profile_currencies := payload.get("profileCurrencies"): 1030 if "data" in raw_profile_currencies: 1031 profile_currencies = self.deserialize_profile_items( 1032 raw_profile_currencies["data"] 1033 ) 1034 1035 profile_inventories: typing.Optional[ 1036 collections.Sequence[profile.ProfileItemImpl] 1037 ] = None 1038 if raw_profile_inventories := payload.get("profileInventory"): 1039 if "data" in raw_profile_inventories: 1040 profile_inventories = self.deserialize_profile_items( 1041 raw_profile_inventories["data"] 1042 ) 1043 1044 profile_records: typing.Optional[ 1045 collections.Mapping[int, records.Record] 1046 ] = None 1047 1048 if raw_profile_records_ := payload.get("profileRecords"): 1049 profile_records = self.deserialize_profile_records(raw_profile_records_) 1050 1051 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1052 if raw_characters := payload.get("characters"): 1053 characters = self.deserialize_characters(raw_characters) 1054 1055 character_records: typing.Optional[ 1056 collections.Mapping[int, records.CharacterRecord] 1057 ] = None 1058 1059 if raw_character_records := payload.get("characterRecords"): 1060 # Had to do it in two steps.. 1061 to_update: typedefs.JSONObject = {} 1062 for _, data in raw_character_records["data"].items(): 1063 for record_id, record in data.items(): 1064 to_update[record_id] = record 1065 1066 character_records = { 1067 int(rec_id): self.deserialize_character_records( 1068 rec, record_hashes=to_update.get("featuredRecordHashes") 1069 ) 1070 for rec_id, rec in to_update["records"].items() 1071 } 1072 1073 character_equipments: typing.Optional[ 1074 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1075 ] = None 1076 if raw_character_equips := payload.get("characterEquipment"): 1077 character_equipments = self.deserialize_character_equipments( 1078 raw_character_equips 1079 ) 1080 1081 character_inventories: typing.Optional[ 1082 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1083 ] = None 1084 if raw_character_inventories := payload.get("characterInventories"): 1085 if "data" in raw_character_inventories: 1086 character_inventories = self.deserialize_character_equipments( 1087 raw_character_inventories 1088 ) 1089 1090 character_activities: typing.Optional[ 1091 collections.Mapping[int, activity.CharacterActivity] 1092 ] = None 1093 if raw_char_acts := payload.get("characterActivities"): 1094 character_activities = self.deserialize_character_activities(raw_char_acts) 1095 1096 character_render_data: typing.Optional[ 1097 collections.Mapping[int, character.RenderedData] 1098 ] = None 1099 if raw_character_render_data := payload.get("characterRenderData"): 1100 character_render_data = self.deserialize_characters_render_data( 1101 raw_character_render_data 1102 ) 1103 1104 character_progressions: typing.Optional[ 1105 collections.Mapping[int, character.CharacterProgression] 1106 ] = None 1107 1108 if raw_character_progressions := payload.get("characterProgressions"): 1109 character_progressions = self.deserialize_character_progressions_mapping( 1110 raw_character_progressions 1111 ) 1112 1113 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1114 if raw_profile_string_vars := payload.get("profileStringVariables"): 1115 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1116 1117 character_string_vars: typing.Optional[ 1118 collections.Mapping[int, collections.Mapping[int, int]] 1119 ] = None 1120 if raw_character_string_vars := payload.get("characterStringVariables"): 1121 character_string_vars = { 1122 int(char_id): data["integerValuesByHash"] 1123 for char_id, data in raw_character_string_vars["data"].items() 1124 } 1125 1126 metrics: typing.Optional[ 1127 collections.Sequence[ 1128 collections.Mapping[ 1129 int, tuple[bool, typing.Optional[records.Objective]] 1130 ] 1131 ] 1132 ] = None 1133 root_node_hash: typing.Optional[int] = None 1134 1135 if raw_metrics := payload.get("metrics"): 1136 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1137 metrics = [ 1138 { 1139 int(metrics_hash): ( 1140 data["invisible"], 1141 self.deserialize_objectives(data["objectiveProgress"]) 1142 if "objectiveProgress" in data 1143 else None, 1144 ) 1145 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1146 } 1147 ] 1148 transitory: typing.Optional[fireteams.FireteamParty] = None 1149 if raw_transitory := payload.get("profileTransitoryData"): 1150 if "data" in raw_transitory: 1151 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1152 1153 item_components: typing.Optional[components.ItemsComponent] = None 1154 if raw_item_components := payload.get("itemComponents"): 1155 item_components = self.deserialize_items_component(raw_item_components) 1156 1157 profile_plugsets: typing.Optional[ 1158 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1159 ] = None 1160 1161 if raw_profile_plugs := payload.get("profilePlugSets"): 1162 profile_plugsets = { 1163 int(index): [self.deserialize_plug_item_state(state) for state in data] 1164 for index, data in raw_profile_plugs["data"]["plugs"].items() 1165 } 1166 1167 character_plugsets: typing.Optional[ 1168 collections.Mapping[ 1169 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1170 ] 1171 ] = None 1172 if raw_char_plugsets := payload.get("characterPlugSets"): 1173 character_plugsets = { 1174 int(char_id): { 1175 int(index): [ 1176 self.deserialize_plug_item_state(state) for state in data 1177 ] 1178 for index, data in inner["plugs"].items() 1179 } 1180 for char_id, inner in raw_char_plugsets["data"].items() 1181 } 1182 1183 character_collectibles: typing.Optional[ 1184 collections.Mapping[int, items.Collectible] 1185 ] = None 1186 if raw_character_collectibles := payload.get("characterCollectibles"): 1187 character_collectibles = { 1188 int(char_id): self._deserialize_collectible(data) 1189 for char_id, data in raw_character_collectibles["data"].items() 1190 } 1191 1192 profile_collectibles: typing.Optional[items.Collectible] = None 1193 if raw_profile_collectibles := payload.get("profileCollectibles"): 1194 profile_collectibles = self._deserialize_collectible( 1195 raw_profile_collectibles["data"] 1196 ) 1197 1198 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1199 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1200 profile_nodes = { 1201 int(node_hash): self._deserialize_node(node) 1202 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1203 } 1204 1205 character_nodes: typing.Optional[ 1206 collections.Mapping[int, collections.Mapping[int, records.Node]] 1207 ] = None 1208 if raw_character_nodes := payload.get("characterPresentationNodes"): 1209 character_nodes = { 1210 int(char_id): { 1211 int(node_hash): self._deserialize_node(node) 1212 for node_hash, node in each_character["nodes"].items() 1213 } 1214 for char_id, each_character in raw_character_nodes["data"].items() 1215 } 1216 1217 platform_silver: typing.Optional[ 1218 collections.Mapping[str, profile.ProfileItemImpl] 1219 ] = None 1220 if raw_platform_silver := payload.get("platformSilver"): 1221 if "data" in raw_platform_silver: 1222 platform_silver = { 1223 platform_name: self.deserialize_profile_item(item) 1224 for platform_name, item in raw_platform_silver["data"][ 1225 "platformSilver" 1226 ].items() 1227 } 1228 1229 character_currency_lookups: typing.Optional[ 1230 collections.Mapping[int, collections.Sequence[items.Currency]] 1231 ] = None 1232 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1233 if "data" in raw_char_lookups: 1234 character_currency_lookups = { 1235 int(char_id): self._deserialize_currencies(currencie) 1236 for char_id, currencie in raw_char_lookups["data"].items() 1237 } 1238 1239 character_craftables: typing.Optional[ 1240 collections.Mapping[int, components.CraftablesComponent] 1241 ] = None 1242 if raw_character_craftables := payload.get("characterCraftables"): 1243 1244 if "data" in raw_character_craftables: 1245 character_craftables = { 1246 int(char_id): self.deserialize_craftables_component(craftable) 1247 for char_id, craftable in raw_character_craftables["data"].items() 1248 } 1249 1250 return components.Component( 1251 profiles=profile_, 1252 profile_progression=profile_progression, 1253 profile_currencies=profile_currencies, 1254 profile_inventories=profile_inventories, 1255 profile_records=profile_records, 1256 characters=characters, 1257 character_records=character_records, 1258 character_equipments=character_equipments, 1259 character_inventories=character_inventories, 1260 character_activities=character_activities, 1261 character_render_data=character_render_data, 1262 character_progressions=character_progressions, 1263 profile_string_variables=profile_string_vars, 1264 character_string_variables=character_string_vars, 1265 metrics=metrics, 1266 root_node_hash=root_node_hash, 1267 transitory=transitory, 1268 item_components=item_components, 1269 profile_plugsets=profile_plugsets, 1270 character_plugsets=character_plugsets, 1271 character_collectibles=character_collectibles, 1272 profile_collectibles=profile_collectibles, 1273 profile_nodes=profile_nodes, 1274 character_nodes=character_nodes, 1275 platform_silver=platform_silver, 1276 character_currency_lookups=character_currency_lookups, 1277 character_craftables=character_craftables, 1278 )
Deserialize a JSON payload of Bungie.net profile components information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Component: A component implementation that includes all other components of the deserialized payload.
1280 def deserialize_items_component( 1281 self, payload: typedefs.JSONObject 1282 ) -> components.ItemsComponent: 1283 instances: typing.Optional[ 1284 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1285 ] = None 1286 if raw_instances := payload.get("instances"): 1287 instances = [ 1288 { 1289 int(ins_id): self.deserialize_instanced_item(item) 1290 for ins_id, item in raw_instances["data"].items() 1291 } 1292 ] 1293 1294 render_data: typing.Optional[ 1295 collections.Mapping[int, tuple[bool, dict[int, int]]] 1296 ] = None 1297 if raw_render_data := payload.get("renderData"): 1298 render_data = { 1299 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1300 for ins_id, data in raw_render_data["data"].items() 1301 } 1302 1303 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1304 if raw_stats := payload.get("stats"): 1305 builder: collections.Mapping[int, items.ItemStatsView] = {} 1306 for ins_id, stat in raw_stats["data"].items(): 1307 for _, items_ in stat.items(): 1308 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1309 stats = builder 1310 1311 sockets: typing.Optional[ 1312 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1313 ] = None 1314 if raw_sockets := payload.get("sockets"): 1315 sockets = { 1316 int(ins_id): [ 1317 self.deserialize_item_socket(socket) for socket in item["sockets"] 1318 ] 1319 for ins_id, item in raw_sockets["data"].items() 1320 } 1321 1322 objeectives: typing.Optional[ 1323 collections.Mapping[int, collections.Sequence[records.Objective]] 1324 ] = None 1325 if raw_objectives := payload.get("objectives"): 1326 objeectives = { 1327 int(ins_id): [self.deserialize_objectives(objective)] 1328 for ins_id, data in raw_objectives["data"].items() 1329 for objective in data["objectives"] 1330 } 1331 1332 perks: typing.Optional[ 1333 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1334 ] = None 1335 if raw_perks := payload.get("perks"): 1336 perks = { 1337 int(ins_id): [ 1338 self.deserialize_item_perk(perk) for perk in item["perks"] 1339 ] 1340 for ins_id, item in raw_perks["data"].items() 1341 } 1342 1343 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1344 if raw_plug_states := payload.get("plugStates"): 1345 pending_states: list[items.PlugItemState] = [] 1346 for _, plug in raw_plug_states["data"].items(): 1347 pending_states.append(self.deserialize_plug_item_state(plug)) 1348 plug_states = pending_states 1349 1350 reusable_plugs: typing.Optional[ 1351 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1352 ] = None 1353 if raw_re_plugs := payload.get("reusablePlugs"): 1354 reusable_plugs = { 1355 int(ins_id): [ 1356 self.deserialize_plug_item_state(state) for state in inner 1357 ] 1358 for ins_id, plug in raw_re_plugs["data"].items() 1359 for inner in list(plug["plugs"].values()) 1360 } 1361 1362 plug_objectives: typing.Optional[ 1363 collections.Mapping[ 1364 int, collections.Mapping[int, collections.Collection[records.Objective]] 1365 ] 1366 ] = None 1367 if raw_plug_objectives := payload.get("plugObjectives"): 1368 plug_objectives = { 1369 int(ins_id): { 1370 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1371 for obj_hash, objs in inner["objectivesPerPlug"].items() 1372 } 1373 for ins_id, inner in raw_plug_objectives["data"].items() 1374 } 1375 1376 return components.ItemsComponent( 1377 sockets=sockets, 1378 stats=stats, 1379 render_data=render_data, 1380 instances=instances, 1381 objectives=objeectives, 1382 perks=perks, 1383 plug_states=plug_states, 1384 reusable_plugs=reusable_plugs, 1385 plug_objectives=plug_objectives, 1386 )
Deserialize a JSON objects within the itemComponents key.`
1388 def deserialize_character_component( # type: ignore[call-arg] 1389 self, payload: typedefs.JSONObject 1390 ) -> components.CharacterComponent: 1391 1392 character_: typing.Optional[character.Character] = None 1393 if raw_singuler_character := payload.get("character"): 1394 character_ = self.deserialize_character(raw_singuler_character["data"]) 1395 1396 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1397 if raw_inventory := payload.get("inventory"): 1398 if "data" in raw_inventory: 1399 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1400 1401 activities: typing.Optional[activity.CharacterActivity] = None 1402 if raw_activities := payload.get("activities"): 1403 activities = self.deserialize_character_activity(raw_activities["data"]) 1404 1405 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1406 if raw_equipments := payload.get("equipment"): 1407 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1408 1409 progressions_: typing.Optional[character.CharacterProgression] = None 1410 if raw_progressions := payload.get("progressions"): 1411 progressions_ = self.deserialize_character_progressions( 1412 raw_progressions["data"] 1413 ) 1414 1415 render_data: typing.Optional[character.RenderedData] = None 1416 if raw_render_data := payload.get("renderData"): 1417 render_data = self.deserialize_character_render_data( 1418 raw_render_data["data"] 1419 ) 1420 1421 character_records: typing.Optional[ 1422 collections.Mapping[int, records.CharacterRecord] 1423 ] = None 1424 if raw_char_records := payload.get("records"): 1425 character_records = self.deserialize_characters_records( 1426 raw_char_records["data"] 1427 ) 1428 1429 item_components: typing.Optional[components.ItemsComponent] = None 1430 if raw_item_components := payload.get("itemComponents"): 1431 item_components = self.deserialize_items_component(raw_item_components) 1432 1433 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1434 if raw_nodes := payload.get("presentationNodes"): 1435 nodes = { 1436 int(node_hash): self._deserialize_node(node) 1437 for node_hash, node in raw_nodes["data"]["nodes"].items() 1438 } 1439 1440 collectibles: typing.Optional[items.Collectible] = None 1441 if raw_collectibles := payload.get("collectibles"): 1442 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1443 1444 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1445 if raw_currencies := payload.get("currencyLookups"): 1446 if "data" in raw_currencies: 1447 currency_lookups = self._deserialize_currencies(raw_currencies) 1448 1449 return components.CharacterComponent( 1450 activities=activities, 1451 equipment=equipment, 1452 inventory=inventory, 1453 progressions=progressions_, 1454 render_data=render_data, 1455 character=character_, 1456 character_records=character_records, 1457 profile_records=None, 1458 item_components=item_components, 1459 currency_lookups=currency_lookups, 1460 collectibles=collectibles, 1461 nodes=nodes, 1462 )
Deserialize a JSON payload of Destiny 2 character component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterComponent: A character component.
1490 def deserialize_inventory_results( 1491 self, payload: typedefs.JSONObject 1492 ) -> iterators.Iterator[entity.SearchableEntity]: 1493 suggested_words: list[str] = payload["suggestedWords"] 1494 1495 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1496 return s if not typedefs.is_unknown(s) else undefined.UNDEFINED 1497 1498 return iterators.Iterator( 1499 [ 1500 entity.SearchableEntity( 1501 net=self._net, 1502 hash=data["hash"], 1503 entity_type=data["entityType"], 1504 weight=data["weight"], 1505 suggested_words=suggested_words, 1506 name=data["displayProperties"]["name"], 1507 has_icon=data["displayProperties"]["hasIcon"], 1508 description=_check_unknown( 1509 data["displayProperties"]["description"] 1510 ), 1511 icon=assets.Image(data["displayProperties"]["icon"]), 1512 ) 1513 for data in payload["results"]["results"] 1514 ] 1515 )
Deserialize results of searched Destiny2 entities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]: An iterator over the found searched entities.
1544 def deserialize_inventory_entity( # noqa: C901 Too complex. 1545 self, payload: typedefs.JSONObject, / 1546 ) -> entity.InventoryEntity: 1547 1548 props = self._set_entity_attrs(payload) 1549 objects = self._deserialize_inventory_item_objects(payload) 1550 1551 collectible_hash: typing.Optional[int] = None 1552 if raw_collectible_hash := payload.get("collectibleHash"): 1553 collectible_hash = int(raw_collectible_hash) 1554 1555 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1556 if raw_second_icon := payload.get("secondaryIcon"): 1557 secondary_icon = assets.Image(raw_second_icon) 1558 1559 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1560 if raw_second_overlay := payload.get("secondaryOverlay"): 1561 secondary_overlay = assets.Image(raw_second_overlay) 1562 1563 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1564 if raw_second_special := payload.get("secondarySpecial"): 1565 secondary_special = assets.Image(raw_second_special) 1566 1567 screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1568 if raw_screenshot := payload.get("screenshot"): 1569 screenshot = assets.Image(raw_screenshot) 1570 1571 watermark_icon: typing.Optional[assets.Image] = None 1572 if raw_watermark_icon := payload.get("iconWatermark"): 1573 watermark_icon = assets.Image(raw_watermark_icon) 1574 1575 watermark_shelved: typing.Optional[assets.Image] = None 1576 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1577 watermark_shelved = assets.Image(raw_watermark_shelved) 1578 1579 about: undefined.UndefinedOr[str] = undefined.UNDEFINED 1580 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1581 raw_about 1582 ): 1583 about = raw_about 1584 1585 ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED 1586 if ( 1587 raw_ui_style := payload.get("uiItemDisplayStyle") 1588 ) and not typedefs.is_unknown(raw_ui_style): 1589 ui_item_style = raw_ui_style 1590 1591 tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1592 if ( 1593 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1594 ) and not typedefs.is_unknown(raw_tier_and_name): 1595 tier_and_name = raw_tier_and_name 1596 1597 type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1598 if ( 1599 raw_type_name := payload.get("itemTypeDisplayName") 1600 ) and not typedefs.is_unknown(raw_type_name): 1601 type_name = raw_type_name 1602 1603 display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED 1604 if ( 1605 raw_display_source := payload.get("displaySource") 1606 ) and not typedefs.is_unknown(raw_display_source): 1607 display_source = raw_display_source 1608 1609 lorehash: typing.Optional[int] = None 1610 if raw_lore_hash := payload.get("loreHash"): 1611 lorehash = int(raw_lore_hash) 1612 1613 summary_hash: typing.Optional[int] = None 1614 if raw_summary_hash := payload.get("summaryItemHash"): 1615 summary_hash = raw_summary_hash 1616 1617 breaker_type_hash: typing.Optional[int] = None 1618 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1619 breaker_type_hash = int(raw_breaker_type_hash) 1620 1621 damage_types: typing.Optional[collections.Sequence[int]] = None 1622 if raw_damage_types := payload.get("damageTypes"): 1623 damage_types = [int(type_) for type_ in raw_damage_types] 1624 1625 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1626 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1627 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1628 1629 default_damagetype_hash: typing.Optional[int] = None 1630 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1631 default_damagetype_hash = int(raw_defaultdmg_hash) 1632 1633 emblem_objective_hash: typing.Optional[int] = None 1634 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1635 emblem_objective_hash = int(raw_emblem_obj_hash) 1636 1637 tier_type: typing.Optional[enums.TierType] = None 1638 tier: typing.Optional[enums.ItemTier] = None 1639 bucket_hash: typing.Optional[int] = None 1640 recovery_hash: typing.Optional[int] = None 1641 tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1642 isinstance_item: bool = False 1643 expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED 1644 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED 1645 suppress_expiration: bool = False 1646 max_stack_size: typing.Optional[int] = None 1647 stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED 1648 1649 if inventory := payload.get("inventory"): 1650 tier_type = enums.TierType(int(inventory["tierType"])) 1651 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1652 bucket_hash = int(inventory["bucketTypeHash"]) 1653 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1654 tier_name = inventory["tierTypeName"] 1655 isinstance_item = inventory["isInstanceItem"] 1656 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1657 max_stack_size = int(inventory["maxStackSize"]) 1658 1659 try: 1660 stack_label = inventory["stackUniqueLabel"] 1661 except KeyError: 1662 pass 1663 1664 return entity.InventoryEntity( 1665 net=self._net, 1666 collectible_hash=collectible_hash, 1667 name=props.name, 1668 about=about, 1669 emblem_objective_hash=emblem_objective_hash, 1670 suppress_expiration=suppress_expiration, 1671 max_stack_size=max_stack_size, 1672 stack_label=stack_label, 1673 tier=tier, 1674 tier_type=tier_type, 1675 tier_name=tier_name, 1676 bucket_hash=bucket_hash, 1677 recovery_bucket_hash=recovery_hash, 1678 isinstance_item=isinstance_item, 1679 expire_in_orbit_message=expire_in_orbit_message, 1680 expiration_tooltip=expire_tool_tip, 1681 lore_hash=lorehash, 1682 type_and_tier_name=tier_and_name, 1683 summary_hash=summary_hash, 1684 ui_display_style=ui_item_style, 1685 type_name=type_name, 1686 breaker_type_hash=breaker_type_hash, 1687 description=props.description, 1688 display_source=display_source, 1689 hash=props.hash, 1690 damage_types=damage_types, 1691 index=props.index, 1692 icon=props.icon, 1693 has_icon=props.has_icon, 1694 screenshot=screenshot, 1695 watermark_icon=watermark_icon, 1696 watermark_shelved=watermark_shelved, 1697 secondary_icon=secondary_icon, 1698 secondary_overlay=secondary_overlay, 1699 secondary_special=secondary_special, 1700 type=enums.ItemType(int(payload["itemType"])), 1701 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1702 trait_ids=[trait for trait in payload.get("traitIds", [])], 1703 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1704 item_class=enums.Class(int(payload["classType"])), 1705 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1706 breaker_type=int(payload["breakerType"]), 1707 default_damagetype=int(payload["defaultDamageType"]), 1708 default_damagetype_hash=default_damagetype_hash, 1709 damagetype_hashes=damagetype_hashes, 1710 tooltip_notifications=payload["tooltipNotifications"], 1711 not_transferable=payload["nonTransferrable"], 1712 allow_actions=payload["allowActions"], 1713 is_equippable=payload["equippable"], 1714 objects=objects, 1715 background_colors=payload.get("backgroundColor", {}), 1716 season_hash=payload.get("seasonHash"), 1717 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1718 )
Deserialize a JSON payload of an inventory entity item information.
This can be any item from DestinyInventoryItemDefinition definition.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.InventoryEntity: An entity item.
1720 def deserialize_objective_entity( 1721 self, payload: typedefs.JSONObject, / 1722 ) -> entity.ObjectiveEntity: 1723 props = self._set_entity_attrs(payload) 1724 return entity.ObjectiveEntity( 1725 net=self._net, 1726 hash=props.hash, 1727 index=props.index, 1728 description=props.description, 1729 name=props.name, 1730 has_icon=props.has_icon, 1731 icon=props.icon, 1732 unlock_value_hash=payload["unlockValueHash"], 1733 completion_value=payload["completionValue"], 1734 scope=entity.GatingScope(int(payload["scope"])), 1735 location_hash=payload["locationHash"], 1736 allowed_negative_value=payload["allowNegativeValue"], 1737 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1738 counting_downward=payload["isCountingDownward"], 1739 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1740 progress_description=payload["progressDescription"], 1741 perks=payload["perks"], 1742 stats=payload["stats"], 1743 minimum_visibility=payload["minimumVisibilityThreshold"], 1744 allow_over_completion=payload["allowOvercompletion"], 1745 show_value_style=payload["showValueOnComplete"], 1746 display_only_objective=payload["isDisplayOnlyObjective"], 1747 complete_value_style=entity.ValueUIStyle( 1748 int(payload["completedValueStyle"]) 1749 ), 1750 progress_value_style=entity.ValueUIStyle( 1751 int(payload["inProgressValueStyle"]) 1752 ), 1753 ui_label=payload["uiLabel"], 1754 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1755 )
Deserialize a JSON payload of an objective entity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity.
1783 def deserialize_activity( 1784 self, 1785 payload: typedefs.JSONObject, 1786 /, 1787 ) -> activity.Activity: 1788 period = time.clean_date(payload["period"]) 1789 details = payload["activityDetails"] 1790 ref_id = int(details["referenceId"]) 1791 instance_id = int(details["instanceId"]) 1792 mode = enums.GameMode(details["mode"]) 1793 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1794 is_private = details["isPrivate"] 1795 membership_type = enums.MembershipType(int(details["membershipType"])) 1796 1797 # Since we're using the same fields for post activity method 1798 # this check is required since post activity doesn't values values 1799 values = self._deserialize_activity_values(payload["values"]) 1800 1801 return activity.Activity( 1802 net=self._net, 1803 hash=ref_id, 1804 instance_id=instance_id, 1805 mode=mode, 1806 modes=modes, 1807 is_private=is_private, 1808 membership_type=membership_type, 1809 occurred_at=period, 1810 values=values, 1811 )
Deserialize a JSON payload of an activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Activity: An activity.
1813 def deserialize_activities( 1814 self, payload: typedefs.JSONObject 1815 ) -> iterators.Iterator[activity.Activity]: 1816 return iterators.Iterator( 1817 [ 1818 self.deserialize_activity(activity_) 1819 for activity_ in payload["activities"] 1820 ] 1821 )
Deserialize a JSON payload of an array of activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
1823 def deserialize_extended_weapon_values( 1824 self, payload: typedefs.JSONObject 1825 ) -> activity.ExtendedWeaponValues: 1826 1827 assists: typing.Optional[int] = None 1828 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1829 assists = raw_assists["basic"]["value"] 1830 assists_damage: typing.Optional[int] = None 1831 1832 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1833 assists_damage = raw_assists_damage["basic"]["value"] 1834 1835 return activity.ExtendedWeaponValues( 1836 reference_id=int(payload["referenceId"]), 1837 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1838 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1839 "value" 1840 ], 1841 assists=assists, 1842 assists_damage=assists_damage, 1843 precision_kills_percentage=( 1844 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1845 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1846 "displayValue" 1847 ], 1848 ), 1849 )
Deserialize values of extended weapons JSON object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ExtendedWeaponValues: Information about an extended weapon values.
1872 def deserialize_post_activity_player( 1873 self, payload: typedefs.JSONObject, / 1874 ) -> activity.PostActivityPlayer: 1875 player = payload["player"] 1876 1877 class_hash: typedefs.NoneOr[int] = None 1878 if (class_hash := player.get("classHash")) is not None: 1879 class_hash = class_hash 1880 1881 race_hash: typedefs.NoneOr[int] = None 1882 if (race_hash := player.get("raceHash")) is not None: 1883 race_hash = race_hash 1884 1885 gender_hash: typedefs.NoneOr[int] = None 1886 if (gender_hash := player.get("genderHash")) is not None: 1887 gender_hash = gender_hash 1888 1889 character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED 1890 if ( 1891 character_class := player.get("characterClass") 1892 ) and not typedefs.is_unknown(character_class): 1893 character_class = character_class 1894 1895 character_level: typedefs.NoneOr[int] = None 1896 if (character_level := player.get("characterLevel")) is not None: 1897 character_level = character_level 1898 1899 return activity.PostActivityPlayer( 1900 standing=int(payload["standing"]), 1901 score=int(payload["score"]["basic"]["value"]), 1902 character_id=payload["characterId"], 1903 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1904 character_class=character_class, 1905 character_level=character_level, 1906 race_hash=race_hash, 1907 gender_hash=gender_hash, 1908 class_hash=class_hash, 1909 light_level=int(player["lightLevel"]), 1910 emblem_hash=int(player["emblemHash"]), 1911 values=self._deserialize_activity_values(payload["values"]), 1912 extended_values=self._deserialize_extended_values(payload["extended"]), 1913 )
Deserialize a JSON payload of a post activity player information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivityPlayer: A post activity player object.
1925 def deserialize_post_activity( 1926 self, payload: typedefs.JSONObject 1927 ) -> activity.PostActivity: 1928 period = time.clean_date(payload["period"]) 1929 details = payload["activityDetails"] 1930 ref_id = int(details["referenceId"]) 1931 instance_id = int(details["instanceId"]) 1932 mode = enums.GameMode(details["mode"]) 1933 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1934 is_private = details["isPrivate"] 1935 membership_type = enums.MembershipType(int(details["membershipType"])) 1936 return activity.PostActivity( 1937 net=self._net, 1938 hash=ref_id, 1939 membership_type=membership_type, 1940 instance_id=instance_id, 1941 mode=mode, 1942 modes=modes, 1943 is_private=is_private, 1944 occurred_at=period, 1945 starting_phase=int(payload["startingPhaseIndex"]), 1946 players=[ 1947 self.deserialize_post_activity_player(player) 1948 for player in payload["entries"] 1949 ], 1950 teams=[ 1951 self._deserialize_post_activity_team(team) for team in payload["teams"] 1952 ], 1953 )
Deserialize a JSON payload of a post activity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivity: A post activity object.
1991 def deserialize_aggregated_activity( 1992 self, payload: typedefs.JSONObject 1993 ) -> activity.AggregatedActivity: 1994 return activity.AggregatedActivity( 1995 hash=int(payload["activityHash"]), 1996 values=self._deserialize_aggregated_activity_values(payload["values"]), 1997 )
Deserialize a JSON payload of an aggregated activity.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AggregatedActivity: An aggregated activity object.
1999 def deserialize_aggregated_activities( 2000 self, payload: typedefs.JSONObject 2001 ) -> iterators.Iterator[activity.AggregatedActivity]: 2002 return iterators.Iterator( 2003 [ 2004 self.deserialize_aggregated_activity(activity) 2005 for activity in payload["activities"] 2006 ] 2007 )
Deserialize a JSON payload of an array of aggregated activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]: An iterator over aggregated activities objects.
2009 def deserialize_linked_profiles( 2010 self, payload: typedefs.JSONObject 2011 ) -> profile.LinkedProfile: 2012 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2013 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2014 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2015 2016 if raw_profile := payload.get("profiles"): 2017 for pfile in raw_profile: 2018 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2019 2020 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2021 for raw_error_pfile in raw_profiles_with_errors: 2022 if error_pfile := raw_error_pfile.get("infoCard"): 2023 error_profiles_vec.append( 2024 self.deserialize_destiny_membership(error_pfile) 2025 ) 2026 2027 return profile.LinkedProfile( 2028 net=self._net, 2029 bungie=bungie_user, 2030 profiles=profiles_vec, 2031 profiles_with_errors=error_profiles_vec, 2032 )
Deserialize a JSON payload of Bungie.net hard linked profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.LinkedProfile: A hard linked profile.
2048 def deserialize_public_milestone_content( 2049 self, payload: typedefs.JSONObject 2050 ) -> milestones.MilestoneContent: 2051 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2052 if raw_categories := payload.get("itemCategories"): 2053 for item in raw_categories: 2054 title = undefined.UNDEFINED 2055 if raw_title := item.get("title"): 2056 if raw_title != typedefs.Unknown: 2057 title = raw_title 2058 if raw_hashes := item.get("itemHashes"): 2059 hashes: collections.Sequence[int] = raw_hashes 2060 2061 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2062 2063 about = undefined.UNDEFINED 2064 if (raw_about := payload["about"]) != typedefs.Unknown: 2065 about = raw_about 2066 2067 status = undefined.UNDEFINED 2068 if (raw_status := payload["status"]) != typedefs.Unknown: 2069 status = raw_status 2070 2071 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2072 if raw_tips := payload.get("tips"): 2073 for raw_tip in raw_tips: 2074 if raw_tip == typedefs.Unknown: 2075 raw_tip = undefined.UNDEFINED 2076 tips.append(raw_tip) 2077 2078 return milestones.MilestoneContent( 2079 about=about, status=status, tips=tips, items=items_categoris 2080 )
Deserialize a JSON payload of milestone content information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.MilestoneContent: A milestone content.
2082 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2083 name = undefined.UNDEFINED 2084 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2085 name = raw_name 2086 2087 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2088 2089 if raw_bungie_user := payload.get("bungieNetUser"): 2090 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2091 2092 return friends.Friend( 2093 net=self._net, 2094 id=int(payload["lastSeenAsMembershipId"]), 2095 name=name, 2096 code=payload.get("bungieGlobalDisplayNameCode"), 2097 relationship=enums.Relationship(payload["relationship"]), 2098 user=bungie_user, 2099 online_status=enums.Presence(payload["onlineStatus"]), 2100 online_title=payload["onlineTitle"], 2101 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2102 )
Deserialize a JSON payload of a Bungie friend information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Friend: A friend.
2104 def deserialize_friends( 2105 self, payload: typedefs.JSONObject 2106 ) -> collections.Sequence[friends.Friend]: 2107 mut_seq: typing.MutableSequence[friends.Friend] = [] 2108 if raw_friends := payload.get("friends"): 2109 for friend in raw_friends: 2110 mut_seq.append(self.deserialize_friend(friend)) 2111 return mut_seq
Deserialize a JSON sequence of Bungie friends information.
This is usually used to deserialize the incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of friends.
2113 def deserialize_friend_requests( 2114 self, payload: typedefs.JSONObject 2115 ) -> friends.FriendRequestView: 2116 incoming: typing.MutableSequence[friends.Friend] = [] 2117 outgoing: typing.MutableSequence[friends.Friend] = [] 2118 2119 if raw_incoming_requests := payload.get("incomingRequests"): 2120 for incoming_request in raw_incoming_requests: 2121 incoming.append(self.deserialize_friend(incoming_request)) 2122 2123 if raw_outgoing_requests := payload.get("outgoingRequests"): 2124 for outgoing_request in raw_outgoing_requests: 2125 outgoing.append(self.deserialize_friend(outgoing_request)) 2126 2127 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
Deserialize a JSON sequence of Bungie friend requests information.
This is used for incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.FriendRequestView]: A sequence of incoming and outgoing friends.
2152 def deserialize_fireteams( 2153 self, payload: typedefs.JSONObject 2154 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2155 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2156 2157 result: list[typedefs.JSONObject] 2158 if not (result := payload["results"]): 2159 return None 2160 for elem in result: 2161 fireteams_.append( 2162 self._set_fireteam_fields( 2163 elem, total_results=int(payload["totalResults"]) 2164 ) 2165 ) 2166 return fireteams_
Deserialize a JSON sequence of Bungie fireteams information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteam.
2168 def deserialize_fireteam_destiny_users( 2169 self, payload: typedefs.JSONObject 2170 ) -> fireteams.FireteamUser: 2171 destiny_obj = self.deserialize_destiny_membership(payload) 2172 # We could helpers.just return a DestinyMembership object but this is 2173 # missing the fireteam display name and id fields. 2174 return fireteams.FireteamUser( 2175 net=self._net, 2176 id=destiny_obj.id, 2177 code=destiny_obj.code, 2178 icon=destiny_obj.icon, 2179 types=destiny_obj.types, 2180 type=destiny_obj.type, 2181 is_public=destiny_obj.is_public, 2182 crossave_override=destiny_obj.crossave_override, 2183 name=destiny_obj.name, 2184 last_seen_name=destiny_obj.last_seen_name, 2185 fireteam_display_name=payload["FireteamDisplayName"], 2186 fireteam_membership_id=enums.MembershipType( 2187 payload["FireteamMembershipType"] 2188 ), 2189 )
Deserialize a JSON payload of Bungie fireteam destiny users information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamUser: A fireteam user.
2191 def deserialize_fireteam_members( 2192 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2193 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2194 members_: list[fireteams.FireteamMember] = [] 2195 if members := payload.get("Members" if not alternatives else "Alternates"): 2196 for member in members: 2197 bungie_fields = self.deserialize_partial_bungie_user(member) 2198 members_fields = fireteams.FireteamMember( 2199 destiny_user=self.deserialize_fireteam_destiny_users(member), 2200 has_microphone=member["hasMicrophone"], 2201 character_id=int(member["characterId"]), 2202 date_joined=time.clean_date(member["dateJoined"]), 2203 last_platform_invite_date=time.clean_date( 2204 member["lastPlatformInviteAttemptDate"] 2205 ), 2206 last_platform_invite_result=int( 2207 member["lastPlatformInviteAttemptResult"] 2208 ), 2209 net=self._net, 2210 name=bungie_fields.name, 2211 id=bungie_fields.id, 2212 icon=bungie_fields.icon, 2213 is_public=bungie_fields.is_public, 2214 crossave_override=bungie_fields.crossave_override, 2215 types=bungie_fields.types, 2216 type=bungie_fields.type, 2217 ) 2218 members_.append(members_fields) 2219 else: 2220 return None 2221 return members_
Deserialize a JSON sequence of Bungie fireteam members information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - alternatives (
bool): If set toTrue, Then it will deserialize thealternativesdata in the payload. If not the it will just deserialize themembersdata.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.FireteamUser]]: An optional sequence of the fireteam members.
2223 def deserialize_available_fireteams( 2224 self, 2225 data: typedefs.JSONObject, 2226 *, 2227 no_results: bool = False, 2228 ) -> typing.Union[ 2229 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2230 ]: 2231 fireteams_: list[fireteams.AvailableFireteam] = [] 2232 2233 # This needs to be used outside the results 2234 # JSON key. 2235 if no_results is True: 2236 payload = data 2237 2238 if result := payload.get("results"): 2239 2240 for fireteam in result: 2241 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2242 fireteams_fields = fireteams.AvailableFireteam( 2243 id=found_fireteams.id, 2244 group_id=found_fireteams.group_id, 2245 platform=found_fireteams.platform, 2246 activity_type=found_fireteams.activity_type, 2247 is_immediate=found_fireteams.is_immediate, 2248 is_public=found_fireteams.is_public, 2249 is_valid=found_fireteams.is_valid, 2250 owner_id=found_fireteams.owner_id, 2251 player_slot_count=found_fireteams.player_slot_count, 2252 available_player_slots=found_fireteams.available_player_slots, 2253 available_alternate_slots=found_fireteams.available_alternate_slots, 2254 title=found_fireteams.title, 2255 date_created=found_fireteams.date_created, 2256 locale=found_fireteams.locale, 2257 last_modified=found_fireteams.last_modified, 2258 total_results=found_fireteams.total_results, 2259 members=self.deserialize_fireteam_members(payload), 2260 alternatives=self.deserialize_fireteam_members( 2261 payload, alternatives=True 2262 ), 2263 ) 2264 fireteams_.append(fireteams_fields) 2265 if no_results: 2266 return fireteams_fields 2267 return fireteams_
Deserialize a JSON payload of a sequence of/fireteam information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - no_results (
bool): Whether to deserialize the data fromresultsin the payload or not.
Returns
typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]# noqa (E501): An available fireteam or a sequence of available fireteam.
2269 def deserialize_fireteam_party( 2270 self, payload: typedefs.JSONObject 2271 ) -> fireteams.FireteamParty: 2272 last_destination_hash: typing.Optional[int] = None 2273 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2274 last_destination_hash = int(raw_dest_hash) 2275 2276 return fireteams.FireteamParty( 2277 members=[ 2278 self._deserialize_fireteam_party_member(member) 2279 for member in payload["partyMembers"] 2280 ], 2281 activity=self._deserialize_fireteam_party_current_activity( 2282 payload["currentActivity"] 2283 ), 2284 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2285 last_destination_hash=last_destination_hash, 2286 tracking=payload["tracking"], 2287 )
Deserialize a JSON payload of profileTransitory component response.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamParty: A fireteam party object of the current fireteam.
2334 def deserialize_seasonal_artifact( 2335 self, payload: typedefs.JSONObject 2336 ) -> season.Artifact: 2337 if raw_artifact := payload.get("seasonalArtifact"): 2338 if points := raw_artifact.get("pointProgression"): 2339 points_prog = progressions.Progression( 2340 hash=points["progressionHash"], 2341 level=points["level"], 2342 cap=points["levelCap"], 2343 daily_limit=points["dailyLimit"], 2344 weekly_limit=points["weeklyLimit"], 2345 current_progress=points["currentProgress"], 2346 daily_progress=points["dailyProgress"], 2347 needed=points["progressToNextLevel"], 2348 next_level=points["nextLevelAt"], 2349 ) 2350 2351 if bonus := raw_artifact.get("powerBonusProgression"): 2352 power_bonus_prog = progressions.Progression( 2353 hash=bonus["progressionHash"], 2354 level=bonus["level"], 2355 cap=bonus["levelCap"], 2356 daily_limit=bonus["dailyLimit"], 2357 weekly_limit=bonus["weeklyLimit"], 2358 current_progress=bonus["currentProgress"], 2359 daily_progress=bonus["dailyProgress"], 2360 needed=bonus["progressToNextLevel"], 2361 next_level=bonus["nextLevelAt"], 2362 ) 2363 artifact = season.Artifact( 2364 net=self._net, 2365 hash=raw_artifact["artifactHash"], 2366 power_bonus=raw_artifact["powerBonus"], 2367 acquired_points=raw_artifact["pointsAcquired"], 2368 bonus=power_bonus_prog, 2369 points=points_prog, 2370 ) 2371 return artifact
Deserialize a JSON payload of a Destiny 2 seasonal artifact information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Artifact: A seasonal artifact.
2373 def deserialize_profile_progression( 2374 self, payload: typedefs.JSONObject 2375 ) -> profile.ProfileProgression: 2376 return profile.ProfileProgression( 2377 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2378 checklist={ 2379 int(check_id): checklists 2380 for check_id, checklists in payload["data"]["checklists"].items() 2381 }, 2382 )
Deserialize a JSON payload of a profile progression component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ProfileProgression: A profile progression component.
2384 def deserialize_instanced_item( 2385 self, payload: typedefs.JSONObject 2386 ) -> items.ItemInstance: 2387 damage_type_hash: typing.Optional[int] = None 2388 if raw_damagetype_hash := payload.get("damageTypeHash"): 2389 damage_type_hash = int(raw_damagetype_hash) 2390 2391 required_hashes: typing.Optional[collections.Collection[int]] = None 2392 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2393 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2394 2395 breaker_type: typing.Optional[items.ItemBreakerType] = None 2396 if raw_break_type := payload.get("breakerType"): 2397 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2398 2399 breaker_type_hash: typing.Optional[int] = None 2400 if raw_break_type_hash := payload.get("breakerTypeHash"): 2401 breaker_type_hash = int(raw_break_type_hash) 2402 2403 energy: typing.Optional[items.ItemEnergy] = None 2404 if raw_energy := payload.get("energy"): 2405 energy = self.deserialize_item_energy(raw_energy) 2406 2407 primary_stats = None 2408 if raw_primary_stats := payload.get("primaryStat"): 2409 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2410 2411 return items.ItemInstance( 2412 damage_type=enums.DamageType(int(payload["damageType"])), 2413 damage_type_hash=damage_type_hash, 2414 primary_stat=primary_stats, 2415 item_level=int(payload["itemLevel"]), 2416 quality=int(payload["quality"]), 2417 is_equipped=payload["isEquipped"], 2418 can_equip=payload["canEquip"], 2419 equip_required_level=int(payload["equipRequiredLevel"]), 2420 required_equip_unlock_hashes=required_hashes, 2421 cant_equip_reason=int(payload["cannotEquipReason"]), 2422 breaker_type=breaker_type, 2423 breaker_type_hash=breaker_type_hash, 2424 energy=energy, 2425 )
Deserialize a JSON object into an instanced item.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ItemInstance: An instanced item object.
2427 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2428 energy_hash: typing.Optional[int] = None 2429 if raw_energy_hash := payload.get("energyTypeHash"): 2430 energy_hash = int(raw_energy_hash) 2431 2432 return items.ItemEnergy( 2433 hash=energy_hash, 2434 type=items.ItemEnergyType(int(payload["energyType"])), 2435 capacity=int(payload["energyCapacity"]), 2436 used_energy=int(payload["energyUsed"]), 2437 unused_energy=int(payload["energyUnused"]), 2438 )
2440 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2441 perk_hash: typing.Optional[int] = None 2442 if raw_perk_hash := payload.get("perkHash"): 2443 perk_hash = int(raw_perk_hash) 2444 2445 return items.ItemPerk( 2446 hash=perk_hash, 2447 icon=assets.Image(payload["iconPath"]), 2448 is_active=payload["isActive"], 2449 is_visible=payload["visible"], 2450 )
2452 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2453 plug_hash: typing.Optional[int] = None 2454 if raw_plug_hash := payload.get("plugHash"): 2455 plug_hash = int(raw_plug_hash) 2456 2457 enable_fail_indexes: typing.Optional[list[int]] = None 2458 if raw_indexes := payload.get("enableFailIndexes"): 2459 enable_fail_indexes = [int(index) for index in raw_indexes] 2460 2461 return items.ItemSocket( 2462 plug_hash=plug_hash, 2463 is_enabled=payload["isEnabled"], 2464 enable_fail_indexes=enable_fail_indexes, 2465 is_visible=payload.get("visible"), 2466 )
2475 def deserialize_plug_item_state( 2476 self, payload: typedefs.JSONObject 2477 ) -> items.PlugItemState: 2478 item_hash: typing.Optional[int] = None 2479 if raw_item_hash := payload.get("plugItemHash"): 2480 item_hash = int(raw_item_hash) 2481 2482 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2483 if raw_fail_indexes := payload.get("insertFailIndexes"): 2484 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2485 2486 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2487 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2488 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2489 2490 return items.PlugItemState( 2491 item_hash=item_hash, 2492 insert_fail_indexes=insert_fail_indexes, 2493 enable_fail_indexes=enable_fail_indexes, 2494 is_enabled=payload["enabled"], 2495 can_insert=payload["canInsert"], 2496 )
67@typing.final 68class FireteamActivity(int, enums.Enum): 69 """An enum for the fireteam activities.""" 70 71 ALL = 0 72 CRUCIBLE = 2 73 TRIALS_OF_OSIRIS = 3 74 NIGHTFALL = 4 75 ANY = 5 76 GAMBIT = 6 77 BLIND_WELL = 7 78 NIGHTMARE_HUNTS = 12 79 ALTARS_OF_SORROWS = 14 80 DUNGEON = 15 81 RAID_LW = 20 82 RAID_GOS = 21 83 RAID_DSC = 22 84 EXO_CHALLENGE = 23 85 S12_WRATHBORN = 24 86 EMPIRE_HUNTS = 25 87 S13_BATTLEGROUNDS = 26 88 EXOTIC_QUEST = 27 89 RAID_VOG = 28 90 S14_EXPUNGE = 30 91 S15_ASTRAL_ALIGNMENT = 31 92 S15_SHATTERED_RELAM = 32 93 SHATTERED_THRONE = 33 94 PROPHECY = 34 95 PIT_OF_HERESY = 35 96 DOE = 36 97 """Dares of Eternity.""" 98 DUNGEON_GOA = 37 99 """Grasp of Avarice.""" 100 VOW_OF_THE_DISCPILE = 38 101 CAMPAIGN = 39 102 WELLSPRING = 40 103 S16_BATTLEGROUNDS = 41 104 S17_NIGHTMARE_CONTAINMENT = 44 105 S17_SEVER = 45
An enum for the fireteam activities.
131@typing.final 132class FireteamDate(int, enums.Enum): 133 """An enum for fireteam date ranges.""" 134 135 ALL = 0 136 NOW = 1 137 TODAY = 2 138 TWO_DAYS = 3 139 THIS_WEEK = 4
An enum for fireteam date ranges.
108@typing.final 109class FireteamLanguage(str, enums.Enum): 110 """An enum for fireteams languages filters.""" 111 112 ALL = "" 113 ENGLISH = "en" 114 FRENCH = "fr" 115 ESPANOL = "es" 116 DEUTSCH = "de" 117 ITALIAN = "it" 118 JAPANESE = "ja" 119 PORTUGUESE = "pt-br" 120 RUSSIAN = "ru" 121 POLISH = "pl" 122 KOREAN = "ko" 123 # ? China 124 ZH_CHT = "zh-cht" 125 ZH_CHS = "zh-chs" 126 127 def __str__(self) -> str: 128 return str(self.value)
An enum for fireteams languages filters.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
54@typing.final 55class FireteamPlatform(int, enums.Enum): 56 """An enum for fireteam related to bungie fireteams. 57 This is different from the normal `aiobungie.MembershipType`. 58 """ 59 60 ANY = 0 61 PSN_NETWORK = 1 62 XBOX_LIVE = 2 63 STEAM = 4 64 STADIA = 5
An enum for fireteam related to bungie fireteams.
This is different from the normal aiobungie.MembershipType.
97class Flag(__enum.Flag): 98 """Builtin Python enum flag with extra handlings.""" 99 100 # Needs to type this here for mypy 101 _value_: int 102 103 @property 104 def name(self) -> str: # type: ignore[override] 105 if self._name_ is None: 106 self._name_ = f"UNKNOWN {self._value_}" 107 108 return self._name_ 109 110 @property 111 def value(self) -> int: # type: ignore[override] 112 return self._value_ 113 114 def __str__(self) -> str: 115 return self.name 116 117 def __repr__(self) -> str: 118 return f"<{type(self).__name__}.{self.name}: {self._value_!s}>" 119 120 def __int__(self) -> int: 121 if isinstance(self.value, _ITERABLE): 122 raise TypeError( 123 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 124 ) 125 return int(self.value) 126 127 def __or__(self, other: typing.Union[Flag, int]) -> Flag: 128 return self.__class__(self._value_ | int(other)) 129 130 def __xor__(self, other: typing.Union[Flag, int]) -> Flag: 131 return self.__class__(self._value_ ^ int(other)) 132 133 def __and__(self, other: typing.Union[Flag, int]) -> Flag: 134 return self.__class__(other & int(other)) 135 136 def __invert__(self) -> Flag: 137 return self.__class__(~self._value_) 138 139 def __contains__(self, other: typing.Union[Flag, int]) -> bool: 140 return self.value & int(other) == int(other)
Builtin Python enum flag with extra handlings.
137@attrs.define(auto_exc=True) 138class Forbidden(HTTPException): 139 """Exception that's raised for when status code 403 occurs.""" 140 141 http_status: http.HTTPStatus = attrs.field( 142 default=http.HTTPStatus.FORBIDDEN, init=False 143 )
Exception that's raised for when status code 403 occurs.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class Forbidden.
Inherited Members
- builtins.BaseException
- with_traceback
269@typing.final 270class GameMode(int, Enum): 271 """An Enum for all available gamemodes in Destiny 2.""" 272 273 NONE = 0 274 STORY = 2 275 STRIKE = 3 276 RAID = 4 277 ALLPVP = 5 278 PATROL = 6 279 ALLPVE = 7 280 RESERVED9 = 9 281 CONTROL = 10 282 RESERVED11 = 11 283 CLASH = 12 284 RESERVED13 = 13 285 CRIMSONDOUBLES = 15 286 NIGHTFALL = 16 287 HEROICNIGHTFALL = 17 288 ALLSTRIKES = 18 289 IRONBANNER = 19 290 RESERVED20 = 20 291 RESERVED21 = 21 292 RESERVED22 = 22 293 RESERVED24 = 24 294 ALLMAYHEM = 25 295 RESERVED26 = 26 296 RESERVED27 = 27 297 RESERVED28 = 28 298 RESERVED29 = 29 299 RESERVED30 = 30 300 SUPREMACY = 31 301 PRIVATEMATCHESALL = 32 302 SURVIVAL = 37 303 COUNTDOWN = 38 304 TRIALSOFTHENINE = 39 305 SOCIAL = 40 306 TRIALSCOUNTDOWN = 41 307 TRIALSSURVIVAL = 42 308 IRONBANNERCONTROL = 43 309 IRONBANNERCLASH = 44 310 IRONBANNERSUPREMACY = 45 311 SCOREDNIGHTFALL = 46 312 SCOREDHEROICNIGHTFALL = 47 313 RUMBLE = 48 314 ALLDOUBLES = 49 315 DOUBLES = 50 316 PRIVATEMATCHESCLASH = 51 317 PRIVATEMATCHESCONTROL = 52 318 PRIVATEMATCHESSUPREMACY = 53 319 PRIVATEMATCHESCOUNTDOWN = 54 320 PRIVATEMATCHESSURVIVAL = 55 321 PRIVATEMATCHESMAYHEM = 56 322 PRIVATEMATCHESRUMBLE = 57 323 HEROICADVENTURE = 58 324 SHOWDOWN = 59 325 LOCKDOWN = 60 326 SCORCHED = 61 327 SCORCHEDTEAM = 62 328 GAMBIT = 63 329 ALLPVECOMPETITIVE = 64 330 BREAKTHROUGH = 65 331 BLACKARMORYRUN = 66 332 SALVAGE = 67 333 IRONBANNERSALVAGE = 68 334 PVPCOMPETITIVE = 69 335 PVPQUICKPLAY = 70 336 CLASHQUICKPLAY = 71 337 CLASHCOMPETITIVE = 72 338 CONTROLQUICKPLAY = 73 339 CONTROLCOMPETITIVE = 74 340 GAMBITPRIME = 75 341 RECKONING = 76 342 MENAGERIE = 77 343 VEXOFFENSIVE = 78 344 NIGHTMAREHUNT = 79 345 ELIMINATION = 80 346 MOMENTUM = 81 347 DUNGEON = 82 348 SUNDIAL = 83 349 TRIALS_OF_OSIRIS = 84 350 DARES = 85 351 OFFENSIVE = 86 352 LOSTSECTOR = 87 353 RIFT = 88 354 ZONECONTROL = 89 355 IRONBANNERRIFT = 90
An Enum for all available gamemodes in Destiny 2.
58@typing.final 59class GatingScope(int, enums.Enum): 60 """An enum represents restrictive type of gating that is being performed by an entity. 61 62 This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity 63 applies to everyone equally, or to their specific Profile or Character states. 64 """ 65 66 NONE = 0 67 GLOBAL = 1 68 CLAN = 2 69 PROFILE = 3 70 CHARACTER = 4 71 ITEM = 5 72 ASSUMED_WORST_CASE = 6
An enum represents restrictive type of gating that is being performed by an entity.
This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.
484@typing.final 485class Gender(int, Enum): 486 """An Enum for Destiny Genders.""" 487 488 MALE = 0 489 FEMALE = 1 490 UNKNOWN = 2
An Enum for Destiny Genders.
653@typing.final 654class GroupType(int, Enum): 655 """An enums for the known bungie group types.""" 656 657 GENERAL = 0 658 CLAN = 1
An enums for the known bungie group types.
79@attrs.define(auto_exc=True) 80class HTTPError(AiobungieError): 81 """Base HTTP request errors exception.""" 82 83 message: str 84 """The error message.""" 85 86 http_status: http.HTTPStatus 87 """The response status."""
Base HTTP request errors exception.
2def __init__(self, message, http_status): 3 self.message = message 4 self.http_status = http_status 5 BaseException.__init__(self, self.message,self.http_status)
Method generated by attrs for class HTTPError.
Inherited Members
- builtins.BaseException
- with_traceback
90@attrs.define(auto_exc=True, kw_only=True) 91class HTTPException(HTTPError): 92 """An in-depth HTTP exception that's raised with more information.""" 93 94 error_code: int 95 """The returned Bungie error status code.""" 96 97 http_status: http.HTTPStatus 98 """The request response http status.""" 99 100 throttle_seconds: int 101 """The Bungie response throttle seconds.""" 102 103 url: typing.Optional[typedefs.StrOrURL] 104 """The URL/endpoint caused this error.""" 105 106 body: typing.Any 107 """The response body.""" 108 109 headers: multidict.CIMultiDictProxy[str] 110 """The response headers.""" 111 112 message: str 113 """A Bungie human readable message describes the cause of the error.""" 114 115 error_status: str 116 """A Bungie short error status describes the cause of the error.""" 117 118 message_data: dict[str, str] 119 """A dict of string key, value that includes each cause of the error 120 to a message describes information about that error. 121 """ 122 123 def __str__(self) -> str: 124 if self.message: 125 message_body = self.message 126 127 if self.error_status: 128 error_status_body = self.error_status 129 130 return ( 131 f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: " 132 f"Error status: {error_status_body}, Error message: {message_body} from {self.url} " 133 f"{str(self.body)}" 134 )
An in-depth HTTP exception that's raised with more information.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class HTTPException.
A dict of string key, value that includes each cause of the error to a message describes information about that error.
Inherited Members
- builtins.BaseException
- with_traceback
72class Image: 73 """Representation of an image/avatar/picture at Bungie. 74 75 Example 76 ------- 77 ```py 78 from aiobungie import Image 79 img = Image("img/destiny_content/pgcr/raid_eclipse.jpg") 80 print(img) 81 # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg 82 83 # Stream the image. 84 async for chunk in img: 85 # Byte chunks of the image. 86 print(chunk) 87 88 # Save the image to a file. 89 await img.save("file_name", "/my/path/to/save/to", "jpeg") 90 ``` 91 92 Parameters 93 ---------- 94 path : `str | None` 95 The path to the image. If `None`, the default missing image path will be used. 96 """ 97 98 __slots__ = ("_path",) 99 100 def __init__(self, path: typing.Optional[str] = None) -> None: 101 self._path = path 102 103 @property 104 def is_missing(self) -> bool: 105 return not self._path 106 107 @property 108 def url(self) -> str: 109 """The URL to the image.""" 110 return self.create_url() 111 112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png" 116 117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}" 126 127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err 181 182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader 204 205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk 224 225 def __repr__(self) -> str: 226 return f"Image(url={self.create_url()})" 227 228 def __str__(self) -> str: 229 return self.create_url() 230 231 def __aiter__(self) -> Image: 232 return self 233 234 async def __anext__(self) -> bytes: 235 return await self.read() 236 237 def __await__(self) -> collections.Generator[None, None, bytes]: 238 return self.__anext__().__await__()
Representation of an image/avatar/picture at Bungie.
Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
# Stream the image.
async for chunk in img:
# Byte chunks of the image.
print(chunk)
# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
- path (
str | None): The path to the image. IfNone, the default missing image path will be used.
112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png"
Returns the path to the missing Bungie image.
117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
Creates a full URL to the image path.
Returns
- str: The URL to the image.
127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err
Saves the image to a file.
Parameters
- file_name (
str): A name for the file to save the image to. - path (
pathlib.Path | str): A path tp save the image to.
Other Parameters
- mime_type (
MimeType | str): Optional MIME type of the image.
Raises
FileNotFoundError: If the path provided does not exist.RuntimeError: If the image could not be saved.PermissionError: If the path provided is not writable or does not have write permissions.
182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader
Read this image bytes.
Returns
bytes: The bytes of this image.
205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk
Iterates over the image bytes lazily.
Example
import aiobungie
resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)
Returns
collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
243@attrs.define(auto_exc=True) 244class InternalServerError(HTTPException): 245 """Raised for 5xx internal server errors."""
Raised for 5xx internal server errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class InternalServerError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
719@typing.final 720class ItemBindStatus(int, Enum): 721 """An enum for Destiny 2 items bind status.""" 722 723 NOT_BOUND = 0 724 BOUND_TO_CHARACTER = 1 725 BOUND_TO_ACCOUNT = 2 726 BOUNT_TO_GUILD = 3
An enum for Destiny 2 items bind status.
729@typing.final 730class ItemLocation(int, Enum): 731 """An enum for Destiny 2 items location.""" 732 733 UNKNOWN = 0 734 INVENTORY = 1 735 VAULT = 2 736 VENDOR = 3 737 POSTMASTER = 4
An enum for Destiny 2 items location.
754@typing.final 755class ItemState(Flag): 756 """An enum for Destiny 2 item states.""" 757 758 NONE = 0 759 LOCKED = 1 << 0 760 TRACKED = 1 << 1 761 MASTERWORKED = 1 << 2 762 CRAFTED = 1 << 3 763 """If this bit is set, the item has been 'crafted' by the player.""" 764 HIGHLITED_OBJECTIVE = 1 << 4 765 """If this bit is set, the item is a 'highlighted' objective."""
An enum for Destiny 2 item states.
If this bit is set, the item is a 'highlighted' objective.
586@typing.final 587class ItemSubType(int, Enum): 588 """An enum for Destiny 2 inventory items subtype.""" 589 590 NONE = 0 591 AUTORIFLE = 6 592 SHOTGUN = 7 593 MACHINEGUN = 8 594 HANDCANNON = 9 595 ROCKETLAUNCHER = 10 596 FUSIONRIFLE = 11 597 SNIPERRIFLE = 12 598 PULSERIFLE = 13 599 SCOUTRIFLE = 14 600 SIDEARM = 17 601 SWORD = 18 602 MASK = 19 603 SHADER = 20 604 ORNAMENT = 21 605 FUSIONRIFLELINE = 22 606 GRENADELAUNCHER = 23 607 SUBMACHINEGUN = 24 608 TRACERIFLE = 25 609 HELMETARMOR = 26 610 GAUNTLETSARMOR = 27 611 CHESTARMOR = 28 612 LEGARMOR = 29 613 CLASSARMOR = 30 614 BOW = 31 615 DUMMYREPEATABLEBOUNTY = 32
An enum for Destiny 2 inventory items subtype.
618@typing.final 619class ItemTier(int, Enum): 620 """An enum for a Destiny 2 item tier.""" 621 622 NONE = 0 623 BASIC = 3340296461 624 COMMON = 2395677314 625 RARE = 2127292149 626 LEGENDERY = 4008398120 627 EXOTIC = 2759499571
An enum for a Destiny 2 item tier.
553@typing.final 554class ItemType(int, Enum): 555 """Enums for Destiny2's item types.""" 556 557 NONE = 0 558 CURRENCY = 1 559 ARMOR = 2 560 WEAPON = 3 561 MESSAGE = 7 562 ENGRAM = 8 563 CONSUMABLE = 9 564 EXCHANGEMATERIAL = 10 565 MISSIONREWARD = 11 566 QUESTSTEP = 12 567 QUESTSTEPCOMPLETE = 13 568 EMBLEM = 14 569 QUEST = 15 570 SUBCLASS = 16 571 CLANBANNER = 17 572 AURA = 18 573 MOD = 19 574 DUMMY = 20 575 SHIP = 21 576 VEHICLE = 22 577 EMOTE = 23 578 GHOST = 24 579 PACKAGE = 25 580 BOUNTY = 26 581 WRAPPER = 27 582 SEASONALARTIFACT = 28 583 FINISHER = 29
Enums for Destiny2's item types.
45class Iterator(typing.Generic[Item]): 46 """A Flat, In-Memory iterator for sequenced based data. 47 48 Example 49 ------- 50 ```py 51 iterator = Iterator([1, 2, 3]) 52 53 # Map the results. 54 for item in iterator.map(lambda item: item * 2): 55 print(item) 56 # 2 57 # 4 58 59 # Indexing is also supported. 60 print(iterator[0]) 61 # 1 62 63 # Normal iteration. 64 for item in iterator: 65 print(item) 66 # 1 67 # 2 68 # 3 69 70 # Union two iterators. 71 iterator2 = Iterator([4, 5, 6]) 72 final = iterator | iterator2 73 # <Iterator([1, 2, 3, 4, 5, 6])> 74 ``` 75 76 Parameters 77 ---------- 78 items: `collections.Iterable[Item]` 79 The items to iterate over. 80 """ 81 82 __slots__ = ("_items",) 83 84 def __init__(self, items: collections.Iterable[Item]) -> None: 85 self._items = iter(items) 86 87 @typing.overload 88 def collect(self) -> list[Item]: 89 ... 90 91 @typing.overload 92 def collect(self, casting: _B) -> list[_B]: 93 ... 94 95 def collect( 96 self, casting: typing.Optional[_B] = None 97 ) -> typing.Union[list[Item], list[_B]]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = Iterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items) 120 121 def next(self) -> Item: 122 """Returns the next item in the iterator. 123 124 Example 125 ------- 126 ```py 127 iterator = Iterator(["1", "2", "3"]) 128 item = iterator.next() 129 assert item == "1" 130 item = iterator.next() 131 assert item == "2" 132 ``` 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 try: 140 return self.__next__() 141 except StopIteration: 142 self._ok() 143 144 def map( 145 self, predicate: collections.Callable[[Item], OtherItem] 146 ) -> Iterator[OtherItem]: 147 """Maps each item in the iterator to its predicated value. 148 149 Example 150 ------- 151 ```py 152 iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value)) 153 print(iterator) 154 # <Iterator([1, 2, 3])> 155 ``` 156 157 Parameters 158 ---------- 159 predicate: `collections.Callable[[Item], OtherItem]` 160 The function to map each item in the iterator to its predicated value. 161 162 Returns 163 ------- 164 `Iterator[OtherItem]` 165 The mapped iterator. 166 167 Raises 168 ------ 169 `StopIteration` 170 If no elements are left in the iterator. 171 """ 172 return Iterator(map(predicate, self._items)) 173 174 def take(self, n: int) -> Iterator[Item]: 175 """Take the first number of items until the number of items are yielded or 176 the end of the iterator is reached. 177 178 Example 179 ------- 180 ```py 181 iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 182 print(iterator.take(2)) 183 # <Iterator([GameMode.RAID, GameMode.STRIKE])> 184 ``` 185 186 Parameters 187 ---------- 188 n: `int` 189 The number of items to take. 190 191 Raises 192 ------ 193 `StopIteration` 194 If no elements are left in the iterator. 195 """ 196 return Iterator(itertools.islice(self._items, n)) 197 198 def take_while( 199 self, predicate: collections.Callable[[Item], bool] 200 ) -> Iterator[Item]: 201 """Yields items from the iterator while predicate returns `True`. 202 203 Example 204 ------- 205 ```py 206 iterator = Iterator([STEAM, XBOX, STADIA]) 207 print(iterator.take_while(lambda platform: platform is not XBOX)) 208 # <Iterator([STEAM])> 209 ``` 210 211 Parameters 212 ---------- 213 predicate: `collections.Callable[[Item], bool]` 214 The function to predicate each item in the iterator. 215 216 Raises 217 ------ 218 `StopIteration` 219 If no elements are left in the iterator. 220 """ 221 return Iterator(itertools.takewhile(predicate, self._items)) 222 223 def drop_while( 224 self, predicate: collections.Callable[[Item], bool] 225 ) -> Iterator[Item]: 226 """Yields items from the iterator while predicate returns `False`. 227 228 Example 229 ------- 230 ```py 231 iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 232 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 233 # <Iterator([DestinyMembership(name="Bob")])> 234 ``` 235 236 Parameters 237 ---------- 238 predicate: `collections.Callable[[Item], bool]` 239 The function to predicate each item in the iterator. 240 241 Raises 242 ------ 243 `StopIteration` 244 If no elements are left in the iterator. 245 """ 246 return Iterator(itertools.dropwhile(predicate, self._items)) 247 248 def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]: 249 """Filters the iterator to only yield items that match the predicate. 250 251 Example 252 ------- 253 ```py 254 names = Iterator(["Jim", "Bob", "Mike", "Jess"]) 255 print(names.filter(lambda n: n != "Jim")) 256 # <Iterator(["Bob", "Mike", "Jess"])> 257 ``` 258 """ 259 return Iterator(filter(predicate, self._items)) 260 261 def skip(self, n: int) -> Iterator[Item]: 262 """Skips the first number of items in the iterator. 263 264 Example 265 ------- 266 ```py 267 iterator = Iterator([STEAM, XBOX, STADIA]) 268 print(iterator.skip(1)) 269 # <Iterator([XBOX, STADIA])> 270 ``` 271 """ 272 return Iterator(itertools.islice(self._items, n, None)) 273 274 def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]: 275 """Zips the iterator with another iterable. 276 277 Example 278 ------- 279 ```py 280 iterator = Iterator([1, 3, 5]) 281 other = Iterator([2, 4, 6]) 282 for item, other_item in iterator.zip(other): 283 print(item, other_item) 284 # <Iterator([(1, 2), (3, 4), (5, 6)])> 285 ``` 286 287 Parameters 288 ---------- 289 other: `Iterator[OtherItem]` 290 The iterable to zip with. 291 292 Raises 293 ------ 294 `StopIteration` 295 If no elements are left in the iterator. 296 """ 297 return Iterator(zip(self._items, other)) 298 299 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 300 """`True` if all items in the iterator match the predicate. 301 302 Example 303 ------- 304 ```py 305 iterator = Iterator([1, 2, 3]) 306 while iterator.all(lambda item: isinstance(item, int)): 307 print("Still all integers") 308 continue 309 # Still all integers 310 ``` 311 312 Parameters 313 ---------- 314 predicate: `collections.Callable[[Item], bool]` 315 The function to test each item in the iterator. 316 317 Raises 318 ------ 319 `StopIteration` 320 If no elements are left in the iterator. 321 """ 322 return all(predicate(item) for item in self) 323 324 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 325 """`True` if any items in the iterator match the predicate. 326 327 Example 328 ------- 329 ```py 330 iterator = Iterator([1, 2, 3]) 331 if iterator.any(lambda item: isinstance(item, int)): 332 print("At least one item is an int.") 333 # At least one item is an int. 334 ``` 335 336 Parameters 337 ---------- 338 predicate: `collections.Callable[[Item], bool]` 339 The function to test each item in the iterator. 340 341 Raises 342 ------ 343 `StopIteration` 344 If no elements are left in the iterator. 345 """ 346 return any(predicate(item) for item in self) 347 348 def sort( 349 self, 350 *, 351 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 352 reverse: bool = False, 353 ) -> Iterator[Item]: 354 """Sorts the iterator. 355 356 Example 357 ------- 358 ```py 359 iterator = Iterator([3, 1, 6, 7]) 360 print(iterator.sort(key=lambda item: item)) 361 # <Iterator([1, 3, 6, 7])> 362 ``` 363 364 Parameters 365 ---------- 366 key: `collections.Callable[[Item], Any]` 367 The function to sort by. 368 reverse: `bool` 369 Whether to reverse the sort. 370 371 Raises 372 ------ 373 `StopIteration` 374 If no elements are left in the iterator. 375 """ 376 return Iterator(sorted(self._items, key=key, reverse=reverse)) 377 378 def first(self) -> Item: 379 """Returns the first item in the iterator. 380 381 Example 382 ------- 383 ```py 384 iterator = Iterator([3, 1, 6, 7]) 385 print(iterator.first()) 386 3 387 ``` 388 389 Raises 390 ------ 391 `StopIteration` 392 If no elements are left in the iterator. 393 """ 394 return self.take(1).next() 395 396 def reversed(self) -> Iterator[Item]: 397 """Returns a new iterator that yields the items in the iterator in reverse order. 398 399 Example 400 ------- 401 ```py 402 iterator = Iterator([3, 1, 6, 7]) 403 print(iterator.reversed()) 404 # <Iterator([7, 6, 1, 3])> 405 ``` 406 407 Raises 408 ------ 409 `StopIteration` 410 If no elements are left in the iterator. 411 """ 412 return Iterator(reversed(self.collect())) 413 414 def count(self) -> int: 415 """Returns the number of items in the iterator. 416 417 Example 418 ------- 419 ```py 420 iterator = Iterator([3, 1, 6, 7]) 421 print(iterator.count()) 422 4 423 ``` 424 """ 425 count = 0 426 for _ in self: 427 count += 1 428 429 return count 430 431 def union(self, other: Iterator[Item]) -> Iterator[Item]: 432 """Returns a new iterator that yields all items from both iterators. 433 434 Example 435 ------- 436 ```py 437 iterator = Iterator([1, 2, 3]) 438 other = Iterator([4, 5, 6]) 439 print(iterator.union(other)) 440 # <Iterator([1, 2, 3, 4, 5, 6])> 441 ``` 442 443 Parameters 444 ---------- 445 other: `Iterator[Item]` 446 The iterable to union with. 447 448 Raises 449 ------ 450 `StopIteration` 451 If no elements are left in the iterator. 452 """ 453 return Iterator(itertools.chain(self._items, other)) 454 455 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 456 """Calls the function on each item in the iterator. 457 458 Example 459 ------- 460 ```py 461 iterator = Iterator([1, 2, 3]) 462 iterator.for_each(lambda item: print(item)) 463 # 1 464 # 2 465 # 3 466 ``` 467 468 Parameters 469 ---------- 470 func: `typeshed.Callable[[Item], None]` 471 The function to call on each item in the iterator. 472 """ 473 for item in self: 474 func(item) 475 476 async def async_for_each( 477 self, 478 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 479 ) -> None: 480 """Calls the async function on each item in the iterator concurrently. 481 482 Example 483 ------- 484 ```py 485 async def signup(username: str) -> None: 486 async with aiohttp.request('POST', '...') as r: 487 # Actual logic. 488 ... 489 490 async def main(): 491 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 492 await users.async_for_each(lambda username: signup(username)) 493 ``` 494 495 Parameters 496 ---------- 497 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 498 The async function to call on each item in the iterator. 499 """ 500 await _helpers.awaits(*(func(item) for item in self)) 501 502 def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]: 503 """Returns a new iterator that yields tuples of the index and item. 504 505 Example 506 ------- 507 ```py 508 iterator = Iterator([1, 2, 3]) 509 for index, item in iterator.enumerate(): 510 print(index, item) 511 # 0 1 512 # 1 2 513 # 2 3 514 ``` 515 516 Raises 517 ------ 518 `StopIteration` 519 If no elements are left in the iterator. 520 """ 521 return Iterator(enumerate(self._items, start=start)) 522 523 def _ok(self) -> typing.NoReturn: 524 raise StopIteration("No more items in the iterator.") from None 525 526 def __getitem__(self, index: int) -> Item: 527 try: 528 return self.skip(index).first() 529 except IndexError: 530 self._ok() 531 532 def __or__(self, other: Iterator[Item]) -> Iterator[Item]: 533 return self.union(other) 534 535 # This is a never. 536 def __setitem__(self) -> typing.NoReturn: 537 raise TypeError( 538 f"{type(self).__name__} doesn't support item assignment." 539 ) from None 540 541 def __repr__(self) -> str: 542 return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>' 543 544 def __len__(self) -> int: 545 return self.count() 546 547 def __iter__(self) -> Iterator[Item]: 548 return self 549 550 def __next__(self) -> Item: 551 try: 552 item = next(self._items) 553 except StopIteration: 554 self._ok() 555 556 return item
A Flat, In-Memory iterator for sequenced based data.
Example
iterator = Iterator([1, 2, 3])
# Map the results.
for item in iterator.map(lambda item: item * 2):
print(item)
# 2
# 4
# Indexing is also supported.
print(iterator[0])
# 1
# Normal iteration.
for item in iterator:
print(item)
# 1
# 2
# 3
# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
- items (
collections.Iterable[Item]): The items to iterate over.
95 def collect( 96 self, casting: typing.Optional[_B] = None 97 ) -> typing.Union[list[Item], list[_B]]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = Iterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items)
Collects all items in the iterator into a list and cast them into an object if provided.
Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
- casting (
T | None): The type to cast the items to. IfNoneis provided, the items will be returned as is.
Raises
StopIteration: If no elements are left in the iterator.
121 def next(self) -> Item: 122 """Returns the next item in the iterator. 123 124 Example 125 ------- 126 ```py 127 iterator = Iterator(["1", "2", "3"]) 128 item = iterator.next() 129 assert item == "1" 130 item = iterator.next() 131 assert item == "2" 132 ``` 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 try: 140 return self.__next__() 141 except StopIteration: 142 self._ok()
Returns the next item in the iterator.
Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
StopIteration: If no elements are left in the iterator.
144 def map( 145 self, predicate: collections.Callable[[Item], OtherItem] 146 ) -> Iterator[OtherItem]: 147 """Maps each item in the iterator to its predicated value. 148 149 Example 150 ------- 151 ```py 152 iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value)) 153 print(iterator) 154 # <Iterator([1, 2, 3])> 155 ``` 156 157 Parameters 158 ---------- 159 predicate: `collections.Callable[[Item], OtherItem]` 160 The function to map each item in the iterator to its predicated value. 161 162 Returns 163 ------- 164 `Iterator[OtherItem]` 165 The mapped iterator. 166 167 Raises 168 ------ 169 `StopIteration` 170 If no elements are left in the iterator. 171 """ 172 return Iterator(map(predicate, self._items))
Maps each item in the iterator to its predicated value.
Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
- predicate (
collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
Iterator[OtherItem]: The mapped iterator.
Raises
StopIteration: If no elements are left in the iterator.
174 def take(self, n: int) -> Iterator[Item]: 175 """Take the first number of items until the number of items are yielded or 176 the end of the iterator is reached. 177 178 Example 179 ------- 180 ```py 181 iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 182 print(iterator.take(2)) 183 # <Iterator([GameMode.RAID, GameMode.STRIKE])> 184 ``` 185 186 Parameters 187 ---------- 188 n: `int` 189 The number of items to take. 190 191 Raises 192 ------ 193 `StopIteration` 194 If no elements are left in the iterator. 195 """ 196 return Iterator(itertools.islice(self._items, n))
Take the first number of items until the number of items are yielded or the end of the iterator is reached.
Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
- n (
int): The number of items to take.
Raises
StopIteration: If no elements are left in the iterator.
198 def take_while( 199 self, predicate: collections.Callable[[Item], bool] 200 ) -> Iterator[Item]: 201 """Yields items from the iterator while predicate returns `True`. 202 203 Example 204 ------- 205 ```py 206 iterator = Iterator([STEAM, XBOX, STADIA]) 207 print(iterator.take_while(lambda platform: platform is not XBOX)) 208 # <Iterator([STEAM])> 209 ``` 210 211 Parameters 212 ---------- 213 predicate: `collections.Callable[[Item], bool]` 214 The function to predicate each item in the iterator. 215 216 Raises 217 ------ 218 `StopIteration` 219 If no elements are left in the iterator. 220 """ 221 return Iterator(itertools.takewhile(predicate, self._items))
Yields items from the iterator while predicate returns True.
Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
223 def drop_while( 224 self, predicate: collections.Callable[[Item], bool] 225 ) -> Iterator[Item]: 226 """Yields items from the iterator while predicate returns `False`. 227 228 Example 229 ------- 230 ```py 231 iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 232 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 233 # <Iterator([DestinyMembership(name="Bob")])> 234 ``` 235 236 Parameters 237 ---------- 238 predicate: `collections.Callable[[Item], bool]` 239 The function to predicate each item in the iterator. 240 241 Raises 242 ------ 243 `StopIteration` 244 If no elements are left in the iterator. 245 """ 246 return Iterator(itertools.dropwhile(predicate, self._items))
Yields items from the iterator while predicate returns False.
Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
248 def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]: 249 """Filters the iterator to only yield items that match the predicate. 250 251 Example 252 ------- 253 ```py 254 names = Iterator(["Jim", "Bob", "Mike", "Jess"]) 255 print(names.filter(lambda n: n != "Jim")) 256 # <Iterator(["Bob", "Mike", "Jess"])> 257 ``` 258 """ 259 return Iterator(filter(predicate, self._items))
Filters the iterator to only yield items that match the predicate.
Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
261 def skip(self, n: int) -> Iterator[Item]: 262 """Skips the first number of items in the iterator. 263 264 Example 265 ------- 266 ```py 267 iterator = Iterator([STEAM, XBOX, STADIA]) 268 print(iterator.skip(1)) 269 # <Iterator([XBOX, STADIA])> 270 ``` 271 """ 272 return Iterator(itertools.islice(self._items, n, None))
Skips the first number of items in the iterator.
Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
274 def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]: 275 """Zips the iterator with another iterable. 276 277 Example 278 ------- 279 ```py 280 iterator = Iterator([1, 3, 5]) 281 other = Iterator([2, 4, 6]) 282 for item, other_item in iterator.zip(other): 283 print(item, other_item) 284 # <Iterator([(1, 2), (3, 4), (5, 6)])> 285 ``` 286 287 Parameters 288 ---------- 289 other: `Iterator[OtherItem]` 290 The iterable to zip with. 291 292 Raises 293 ------ 294 `StopIteration` 295 If no elements are left in the iterator. 296 """ 297 return Iterator(zip(self._items, other))
Zips the iterator with another iterable.
Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
- other (
Iterator[OtherItem]): The iterable to zip with.
Raises
StopIteration: If no elements are left in the iterator.
299 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 300 """`True` if all items in the iterator match the predicate. 301 302 Example 303 ------- 304 ```py 305 iterator = Iterator([1, 2, 3]) 306 while iterator.all(lambda item: isinstance(item, int)): 307 print("Still all integers") 308 continue 309 # Still all integers 310 ``` 311 312 Parameters 313 ---------- 314 predicate: `collections.Callable[[Item], bool]` 315 The function to test each item in the iterator. 316 317 Raises 318 ------ 319 `StopIteration` 320 If no elements are left in the iterator. 321 """ 322 return all(predicate(item) for item in self)
True if all items in the iterator match the predicate.
Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
print("Still all integers")
continue
# Still all integers
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
324 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 325 """`True` if any items in the iterator match the predicate. 326 327 Example 328 ------- 329 ```py 330 iterator = Iterator([1, 2, 3]) 331 if iterator.any(lambda item: isinstance(item, int)): 332 print("At least one item is an int.") 333 # At least one item is an int. 334 ``` 335 336 Parameters 337 ---------- 338 predicate: `collections.Callable[[Item], bool]` 339 The function to test each item in the iterator. 340 341 Raises 342 ------ 343 `StopIteration` 344 If no elements are left in the iterator. 345 """ 346 return any(predicate(item) for item in self)
True if any items in the iterator match the predicate.
Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
print("At least one item is an int.")
# At least one item is an int.
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
348 def sort( 349 self, 350 *, 351 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 352 reverse: bool = False, 353 ) -> Iterator[Item]: 354 """Sorts the iterator. 355 356 Example 357 ------- 358 ```py 359 iterator = Iterator([3, 1, 6, 7]) 360 print(iterator.sort(key=lambda item: item)) 361 # <Iterator([1, 3, 6, 7])> 362 ``` 363 364 Parameters 365 ---------- 366 key: `collections.Callable[[Item], Any]` 367 The function to sort by. 368 reverse: `bool` 369 Whether to reverse the sort. 370 371 Raises 372 ------ 373 `StopIteration` 374 If no elements are left in the iterator. 375 """ 376 return Iterator(sorted(self._items, key=key, reverse=reverse))
Sorts the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
- key (
collections.Callable[[Item], Any]): The function to sort by. - reverse (
bool): Whether to reverse the sort.
Raises
StopIteration: If no elements are left in the iterator.
378 def first(self) -> Item: 379 """Returns the first item in the iterator. 380 381 Example 382 ------- 383 ```py 384 iterator = Iterator([3, 1, 6, 7]) 385 print(iterator.first()) 386 3 387 ``` 388 389 Raises 390 ------ 391 `StopIteration` 392 If no elements are left in the iterator. 393 """ 394 return self.take(1).next()
Returns the first item in the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
StopIteration: If no elements are left in the iterator.
396 def reversed(self) -> Iterator[Item]: 397 """Returns a new iterator that yields the items in the iterator in reverse order. 398 399 Example 400 ------- 401 ```py 402 iterator = Iterator([3, 1, 6, 7]) 403 print(iterator.reversed()) 404 # <Iterator([7, 6, 1, 3])> 405 ``` 406 407 Raises 408 ------ 409 `StopIteration` 410 If no elements are left in the iterator. 411 """ 412 return Iterator(reversed(self.collect()))
Returns a new iterator that yields the items in the iterator in reverse order.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
StopIteration: If no elements are left in the iterator.
414 def count(self) -> int: 415 """Returns the number of items in the iterator. 416 417 Example 418 ------- 419 ```py 420 iterator = Iterator([3, 1, 6, 7]) 421 print(iterator.count()) 422 4 423 ``` 424 """ 425 count = 0 426 for _ in self: 427 count += 1 428 429 return count
Returns the number of items in the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
431 def union(self, other: Iterator[Item]) -> Iterator[Item]: 432 """Returns a new iterator that yields all items from both iterators. 433 434 Example 435 ------- 436 ```py 437 iterator = Iterator([1, 2, 3]) 438 other = Iterator([4, 5, 6]) 439 print(iterator.union(other)) 440 # <Iterator([1, 2, 3, 4, 5, 6])> 441 ``` 442 443 Parameters 444 ---------- 445 other: `Iterator[Item]` 446 The iterable to union with. 447 448 Raises 449 ------ 450 `StopIteration` 451 If no elements are left in the iterator. 452 """ 453 return Iterator(itertools.chain(self._items, other))
Returns a new iterator that yields all items from both iterators.
Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
- other (
Iterator[Item]): The iterable to union with.
Raises
StopIteration: If no elements are left in the iterator.
455 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 456 """Calls the function on each item in the iterator. 457 458 Example 459 ------- 460 ```py 461 iterator = Iterator([1, 2, 3]) 462 iterator.for_each(lambda item: print(item)) 463 # 1 464 # 2 465 # 3 466 ``` 467 468 Parameters 469 ---------- 470 func: `typeshed.Callable[[Item], None]` 471 The function to call on each item in the iterator. 472 """ 473 for item in self: 474 func(item)
Calls the function on each item in the iterator.
Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
- func (
typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
476 async def async_for_each( 477 self, 478 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 479 ) -> None: 480 """Calls the async function on each item in the iterator concurrently. 481 482 Example 483 ------- 484 ```py 485 async def signup(username: str) -> None: 486 async with aiohttp.request('POST', '...') as r: 487 # Actual logic. 488 ... 489 490 async def main(): 491 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 492 await users.async_for_each(lambda username: signup(username)) 493 ``` 494 495 Parameters 496 ---------- 497 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 498 The async function to call on each item in the iterator. 499 """ 500 await _helpers.awaits(*(func(item) for item in self))
Calls the async function on each item in the iterator concurrently.
Example
async def signup(username: str) -> None:
async with aiohttp.request('POST', '...') as r:
# Actual logic.
...
async def main():
users = aiobungie.into_iter(["user_danny", "user_jojo"])
await users.async_for_each(lambda username: signup(username))
Parameters
- func (
collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
502 def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]: 503 """Returns a new iterator that yields tuples of the index and item. 504 505 Example 506 ------- 507 ```py 508 iterator = Iterator([1, 2, 3]) 509 for index, item in iterator.enumerate(): 510 print(index, item) 511 # 0 1 512 # 1 2 513 # 2 3 514 ``` 515 516 Raises 517 ------ 518 `StopIteration` 519 If no elements are left in the iterator. 520 """ 521 return Iterator(enumerate(self._items, start=start))
Returns a new iterator that yields tuples of the index and item.
Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
print(index, item)
# 0 1
# 1 2
# 2 3
Raises
StopIteration: If no elements are left in the iterator.
710@typing.final 711class MembershipOption(int, Enum): 712 """A enum for GroupV2 membership options.""" 713 714 REVIEWD = 0 715 OPEN = 1 716 CLOSED = 2
A enum for GroupV2 membership options.
458@typing.final 459class MembershipType(int, Enum): 460 """An Enum for Bungie membership types.""" 461 462 NONE = 0 463 XBOX = 1 464 PSN = 2 465 STEAM = 3 466 BLIZZARD = 4 467 STADIA = 5 468 EPIC_GAMES_STORE = 6 469 DEMON = 10 470 BUNGIE = 254 471 ALL = -1
An Enum for Bungie membership types.
182@attrs.define(auto_exc=True) 183class MembershipTypeError(BadRequest): 184 """A bad request error raised when passing wrong membership to the request. 185 186 Those fields are useful since it returns the correct membership and id which can be used 187 to make the request again with those fields. 188 189 Example 190 ------- 191 ```py 192 try: 193 profile = await client.fetch_profile( 194 member_id=1, 195 type=aiobungie.MembershipType.STADIA, 196 components=[] 197 ) 198 199 # Membership type is wrong! 200 except aiobungie.MembershipTypeError as err: 201 correct_membersip = err.into_membership() 202 profile_id = err.membership_id 203 204 # Recall the method. 205 profile = await client.fetch_profile( 206 member_id=profile_id, 207 type=correct_membership, 208 components=[] 209 ) 210 ``` 211 """ 212 213 membership_type: str 214 """The errored membership type passed to the request.""" 215 216 membership_id: int 217 """The errored user's membership id.""" 218 219 required_membership: str 220 """The required correct membership for errored user.""" 221 222 def into_membership( 223 self, value: typing.Optional[str] = None 224 ) -> enums.MembershipType: 225 """Turn the required membership from `str` into `aiobungie.Membership` type. 226 227 If value parameter is not provided it will fall back to the required membership. 228 """ 229 if value is None: 230 return _DETERMINE_MSHIP(self.required_membership) 231 return _DETERMINE_MSHIP(value) 232 233 def __str__(self) -> str: 234 return ( 235 f"Expected membership: {self.into_membership().name.replace('_', '').title()}, " 236 f"But got {self.into_membership(self.membership_type)} for id {self.membership_id}" 237 ) 238 239 def __int__(self) -> int: 240 return int(self.membership_id)
A bad request error raised when passing wrong membership to the request.
Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.
Example
try:
profile = await client.fetch_profile(
member_id=1,
type=aiobungie.MembershipType.STADIA,
components=[]
)
# Membership type is wrong!
except aiobungie.MembershipTypeError as err:
correct_membersip = err.into_membership()
profile_id = err.membership_id
# Recall the method.
profile = await client.fetch_profile(
member_id=profile_id,
type=correct_membership,
components=[]
)
2def __init__(self, message, url, body, headers, membership_type, membership_id, required_membership): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = attr_dict['http_status'].default 8 self.membership_type = membership_type 9 self.membership_id = membership_id 10 self.required_membership = required_membership 11 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.membership_type,self.membership_id,self.required_membership)
Method generated by attrs for class MembershipTypeError.
222 def into_membership( 223 self, value: typing.Optional[str] = None 224 ) -> enums.MembershipType: 225 """Turn the required membership from `str` into `aiobungie.Membership` type. 226 227 If value parameter is not provided it will fall back to the required membership. 228 """ 229 if value is None: 230 return _DETERMINE_MSHIP(self.required_membership) 231 return _DETERMINE_MSHIP(value)
Turn the required membership from str into aiobungie.Membership type.
If value parameter is not provided it will fall back to the required membership.
Inherited Members
- builtins.BaseException
- with_traceback
503@typing.final 504class MilestoneType(int, Enum): 505 """An Enum for Destiny 2 milestone types.""" 506 507 UNKNOWN = 0 508 TUTORIAL = 1 509 ONETIME = 2 510 WEEKLY = 3 511 DAILY = 4 512 SPECIAL = 5
An Enum for Destiny 2 milestone types.
146@attrs.define(auto_exc=True) 147class NotFound(HTTPException): 148 """Raised when an unknown resource was not found.""" 149 150 http_status: http.HTTPStatus = attrs.field( 151 default=http.HTTPStatus.NOT_FOUND, init=False 152 )
Raised when an unknown resource was not found.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class NotFound.
Inherited Members
- builtins.BaseException
- with_traceback
94@typing.final 95class ObjectiveUIStyle(int, enums.Enum): 96 NONE = 0 97 HIGHLIGHTED = 1 98 CRAFTING_WEAPON_LEVEL = 2 99 CRAFTING_WEAPON_LEVEL_PROGRESS = 3 100 CRAFTING_WEAPON_TIMESTAMP = 4 101 CRAFTING_MEMENTOS = 5 102 CRAFTING_MEMENTO_TITLE = 6
An enumeration.
230@typing.final 231class Place(int, Enum): 232 """An Enum for Destiny 2 Places and NOT Planets""" 233 234 ORBIT = 2961497387 235 SOCIAL = 4151112093 236 LIGHT_HOUSE = 4276116472 237 EXPLORE = 3497767639
An Enum for Destiny 2 Places and NOT Planets
195@typing.final 196class Planet(int, Enum): 197 """An Enum for all available planets in Destiny 2.""" 198 199 UNKNOWN = 0 200 """Unknown space""" 201 202 EARTH = 3747705955 203 """Earth""" 204 205 DREAMING_CITY = 2877881518 206 """The Dreaming city.""" 207 208 NESSUS = 3526908984 209 """Nessus""" 210 211 MOON = 3325508439 212 """The Moon""" 213 214 COSMODROME = 3990611421 215 """The Cosmodrome""" 216 217 TANGLED_SHORE = 3821439926 218 """The Tangled Shore""" 219 220 VENUS = 3871070152 221 """Venus""" 222 223 EAZ = 541863059 # Exclusive event. 224 """European Aerial Zone""" 225 226 EUROPA = 1729879943 227 """Europa"""
An Enum for all available planets in Destiny 2.
680@typing.final 681class Presence(int, Enum): 682 """An enum for a bungie friend status.""" 683 684 OFFLINE_OR_UNKNOWN = 0 685 ONLINE = 1
An enum for a bungie friend status.
768@typing.final 769class PrivacySetting(int, Enum): 770 """An enum for players's privacy settings.""" 771 772 OPEN = 0 773 CLAN_AND_FRIENDS = 1 774 FRIENDS_ONLY = 2 775 INVITE_ONLY = 3 776 CLOSED = 4
An enum for players's privacy settings.
356class RESTClient(interfaces.RESTInterface): 357 """A RESTful client implementation for Bungie's API. 358 359 This client is designed to only make HTTP requests and return JSON objects 360 to provide RESTful functionality. 361 362 This client is also used within `aiobungie.Client` which deserialize those returned JSON objects 363 using the factory into Pythonic data classes objects which provide Python functionality. 364 365 Example 366 ------- 367 ```py 368 import aiobungie 369 370 async def main(): 371 async with aiobungie.RESTClient("TOKEN") as rest_client: 372 req = await rest_client.fetch_clan_members(4389205) 373 clan_members = req['results'] 374 for member in clan_members: 375 for k, v in member['destinyUserInfo'].items(): 376 print(k, v) 377 ``` 378 379 Parameters 380 ---------- 381 token : `str` 382 A valid application token from Bungie's developer portal. 383 384 Other Parameters 385 ---------------- 386 max_retries : `int` 387 The max retries number to retry if the request hit a `5xx` status code. 388 max_ratelimit_retries : `int` 389 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 390 client_secret : `typing.Optional[str]` 391 An optional application client secret, 392 This is only needed if you're fetching OAuth2 tokens with this client. 393 client_id : `typing.Optional[int]` 394 An optional application client id, 395 This is only needed if you're fetching OAuth2 tokens with this client. 396 enable_debugging : `bool | str` 397 Whether to enable logging responses or not. 398 399 Logging Levels 400 -------------- 401 * `False`: This will disable logging. 402 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 403 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 404 """ 405 406 __slots__ = ( 407 "_token", 408 "_session", 409 "_lock", 410 "_max_retries", 411 "_client_secret", 412 "_client_id", 413 "_metadata", 414 "_max_rate_limit_retries", 415 ) 416 417 def __init__( 418 self, 419 token: str, 420 /, 421 client_secret: typing.Optional[str] = None, 422 client_id: typing.Optional[int] = None, 423 *, 424 max_retries: int = 4, 425 max_ratelimit_retries: int = 3, 426 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 427 ) -> None: 428 self._session: typing.Optional[_Session] = None 429 self._lock: typing.Optional[asyncio.Lock] = None 430 self._client_secret = client_secret 431 self._client_id = client_id 432 self._token: str = token 433 self._max_retries = max_retries 434 self._max_rate_limit_retries = max_ratelimit_retries 435 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 436 437 self._set_debug_level(enable_debugging) 438 439 @property 440 def client_id(self) -> typing.Optional[int]: 441 return self._client_id 442 443 @property 444 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 445 return self._metadata 446 447 @property 448 def is_alive(self) -> bool: 449 return self._session is not None 450 451 @typing.final 452 async def close(self) -> None: 453 session = self._get_session() 454 await session.close() 455 self._session = None 456 457 @typing.final 458 def open(self) -> None: 459 """Open a new client session. This is called internally with contextmanager usage.""" 460 if self.is_alive: 461 raise RuntimeError("Cannot open a new session while it's already open.") 462 463 self._session = _Session.create() 464 465 @typing.final 466 def enable_debugging( 467 self, 468 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 469 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 470 /, 471 ) -> None: 472 self._set_debug_level(level, file) 473 474 @typing.final 475 async def static_request( 476 self, 477 method: typing.Union[RequestMethod, str], 478 path: str, 479 *, 480 auth: typing.Optional[str] = None, 481 json: typing.Optional[dict[str, typing.Any]] = None, 482 ) -> ResponseSig: 483 return await self._request(method, path, auth=auth, json=json) 484 485 @typing.final 486 def build_oauth2_url( 487 self, client_id: typing.Optional[int] = None 488 ) -> typing.Optional[builders.OAuthURL]: 489 client_id = client_id or self._client_id 490 if client_id is None: 491 return None 492 493 return builders.OAuthURL(client_id=client_id) 494 495 @staticmethod 496 def _set_debug_level( 497 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 498 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 499 ) -> None: 500 501 file_handler = logging.FileHandler(file, mode="w") if file else None 502 if level == "TRACE" or level == TRACE: 503 logging.basicConfig( 504 level=TRACE, handlers=[file_handler] if file_handler else None 505 ) 506 507 elif level: 508 logging.basicConfig( 509 level=logging.DEBUG, handlers=[file_handler] if file_handler else None 510 ) 511 512 def _get_session(self) -> _Session: 513 if self._session: 514 return self._session 515 516 raise RuntimeError( 517 "Cannot return a session while its close. Make sure you use `async with` before making requests." 518 ) 519 520 async def _request( 521 self, 522 method: typing.Union[RequestMethod, str], 523 route: str, 524 *, 525 base: bool = False, 526 oauth2: bool = False, 527 auth: typing.Optional[str] = None, 528 unwrapping: typing.Literal["json", "read"] = "json", 529 json: typing.Optional[dict[str, typing.Any]] = None, 530 headers: typing.Optional[dict[str, typing.Any]] = None, 531 data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None, 532 ) -> ResponseSig: 533 534 retries: int = 0 535 session = self._get_session() 536 headers = headers or {} 537 538 headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT) 539 headers["X-API-KEY"] = self._token 540 541 if auth is not None: 542 headers[_AUTH_HEADER] = f"Bearer {auth}" 543 544 # Handling endpoints 545 endpoint = url.BASE 546 547 if not base: 548 endpoint = endpoint + url.REST_EP 549 550 if oauth2: 551 headers["Content-Type"] = "application/x-www-form-urlencoded" 552 endpoint = endpoint + url.TOKEN_EP 553 554 if self._lock is None: 555 self._lock = asyncio.Lock() 556 557 while True: 558 try: 559 async with (stack := contextlib.AsyncExitStack()): 560 await stack.enter_async_context(self._lock) 561 562 # We make the request here. 563 taken_time = time.monotonic() 564 response = await stack.enter_async_context( 565 session.client_session.request( 566 method=method, 567 url=f"{endpoint}/{route}", 568 json=json, 569 headers=headers, 570 data=data, 571 ) 572 ) 573 response_time = (time.monotonic() - taken_time) * 1_000 574 575 _LOG.debug( 576 "%s %s %s Time %.4fms", 577 method, 578 f"{endpoint}/{route}", 579 f"{response.status} {response.reason}", 580 response_time, 581 ) 582 583 await self._handle_ratelimit( 584 response, method, route, self._max_rate_limit_retries 585 ) 586 587 if response.status == http.HTTPStatus.NO_CONTENT: 588 return None 589 590 if 300 > response.status >= 200: 591 if unwrapping == "read": 592 # We need to read the bytes for the manifest response. 593 return await response.read() 594 595 if response.content_type == _APP_JSON: 596 json_data = await response.json() 597 598 _LOG.debug( 599 "%s %s %s Time %.4fms", 600 method, 601 f"{endpoint}/{route}", 602 f"{response.status} {response.reason}", 603 response_time, 604 ) 605 606 if _LOG.isEnabledFor(TRACE): 607 headers.update(response.headers) # type: ignore 608 609 _LOG.log( 610 TRACE, 611 "%s", 612 error.stringify_http_message(headers), 613 ) 614 615 # Return the response. 616 # oauth2 responses are not packed inside a Response object. 617 if oauth2: 618 return json_data # type: ignore[no-any-return] 619 620 return json_data["Response"] # type: ignore[no-any-return] 621 622 if ( 623 response.status in _RETRY_5XX 624 and retries < self._max_retries # noqa: W503 625 ): 626 backoff_ = backoff.ExponentialBackOff(maximum=6) 627 sleep_time = next(backoff_) 628 _LOG.warning( 629 "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i", 630 response.status, 631 response.reason, 632 sleep_time, 633 self._max_retries - retries, 634 ) 635 636 retries += 1 637 await asyncio.sleep(sleep_time) 638 continue 639 640 raise await error.raise_error(response) 641 # eol 642 except _Dyn: 643 continue 644 645 if not typing.TYPE_CHECKING: 646 647 def __enter__(self) -> typing.NoReturn: 648 cls = type(self) 649 raise TypeError( 650 f"{cls.__qualname__} is async only, use 'async with' instead." 651 ) 652 653 def __exit__( 654 self, 655 exception_type: typing.Optional[type[BaseException]], 656 exception: typing.Optional[BaseException], 657 exception_traceback: typing.Optional[types.TracebackType], 658 ) -> None: 659 ... 660 661 async def __aenter__(self) -> RESTClient: 662 self.open() 663 return self 664 665 async def __aexit__( 666 self, 667 exception_type: typing.Optional[type[BaseException]], 668 exception: typing.Optional[BaseException], 669 exception_traceback: typing.Optional[types.TracebackType], 670 ) -> None: 671 await self.close() 672 673 # We don't want this to be super complicated. 674 @staticmethod 675 @typing.final 676 async def _handle_ratelimit( 677 response: aiohttp.ClientResponse, 678 method: str, 679 route: str, 680 max_ratelimit_retries: int = 3, 681 ) -> None: 682 683 if response.status != http.HTTPStatus.TOO_MANY_REQUESTS: 684 return 685 686 if response.content_type != _APP_JSON: 687 raise error.HTTPError( 688 f"Being ratelimited on non JSON request, {response.content_type}.", 689 http.HTTPStatus.TOO_MANY_REQUESTS, 690 ) 691 692 count: int = 0 693 json: typedefs.JSONObject = await response.json() 694 retry_after = float(json["ThrottleSeconds"]) 695 696 while True: 697 if count == max_ratelimit_retries: 698 raise _Dyn 699 700 if retry_after <= 0: 701 # We sleep for a little bit to avoid funky behavior. 702 sleep_time = float(random.random() + 0.93) / 2 703 704 _LOG.warning( 705 "We're being ratelimited with method %s route %s. Sleeping for %.2fs.", 706 method, 707 route, 708 sleep_time, 709 ) 710 count += 1 711 await asyncio.sleep(sleep_time) 712 continue 713 714 raise error.RateLimitedError( 715 body=json, 716 url=str(response.real_url), 717 retry_after=retry_after, 718 ) 719 720 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 721 722 if not isinstance(self._client_id, int): 723 raise TypeError( 724 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 725 ) 726 727 if not isinstance(self._client_secret, str): 728 raise TypeError( 729 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 730 ) 731 732 headers = { 733 "client_secret": self._client_secret, 734 } 735 736 data = ( 737 f"grant_type=authorization_code&code={code}" 738 f"&client_id={self._client_id}&client_secret={self._client_secret}" 739 ) 740 741 response = await self._request( 742 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 743 ) 744 assert isinstance(response, dict) 745 return builders.OAuth2Response.build_response(response) 746 747 async def refresh_access_token( 748 self, refresh_token: str, / 749 ) -> builders.OAuth2Response: 750 if not isinstance(self._client_id, int): 751 raise TypeError( 752 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 753 ) 754 755 if not isinstance(self._client_secret, str): 756 raise TypeError( 757 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 758 ) 759 760 data = { 761 "grant_type": "refresh_token", 762 "refresh_token": refresh_token, 763 "client_id": self._client_id, 764 "client_secret": self._client_secret, 765 "Content-Type": "application/x-www-form-urlencoded", 766 } 767 768 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 769 assert isinstance(response, dict) 770 return builders.OAuth2Response.build_response(response) 771 772 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 773 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 774 resp = await self._request( 775 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 776 ) 777 assert isinstance(resp, dict) 778 return resp 779 780 async def fetch_user_themes(self) -> typedefs.JSONArray: 781 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 782 resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/") 783 assert isinstance(resp, list) 784 return resp 785 786 async def fetch_membership_from_id( 787 self, 788 id: int, 789 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 790 /, 791 ) -> typedefs.JSONObject: 792 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 793 resp = await self._request( 794 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 795 ) 796 assert isinstance(resp, dict) 797 return resp 798 799 async def fetch_player( 800 self, 801 name: str, 802 code: int, 803 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 804 /, 805 ) -> typedefs.JSONArray: 806 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 807 resp = await self._request( 808 RequestMethod.POST, 809 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 810 json={"displayName": name, "displayNameCode": code}, 811 ) 812 assert isinstance(resp, list) 813 return resp 814 815 async def search_users(self, name: str, /) -> typedefs.JSONObject: 816 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 817 resp = await self._request( 818 RequestMethod.POST, 819 "User/Search/GlobalName/0", 820 json={"displayNamePrefix": name}, 821 ) 822 assert isinstance(resp, dict) 823 return resp 824 825 async def fetch_clan_from_id( 826 self, id: int, /, access_token: typing.Optional[str] = None 827 ) -> typedefs.JSONObject: 828 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 829 resp = await self._request( 830 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 831 ) 832 assert isinstance(resp, dict) 833 return resp 834 835 async def fetch_clan( 836 self, 837 name: str, 838 /, 839 access_token: typing.Optional[str] = None, 840 *, 841 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 842 ) -> typedefs.JSONObject: 843 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 844 resp = await self._request( 845 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 846 ) 847 assert isinstance(resp, dict) 848 return resp 849 850 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 851 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 852 resp = await self._request( 853 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 854 ) 855 assert isinstance(resp, dict) 856 return resp 857 858 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 859 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 860 resp = await self._request( 861 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 862 ) 863 assert isinstance(resp, list) 864 return resp 865 866 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 867 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 868 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 869 assert isinstance(resp, dict) 870 return resp 871 872 async def fetch_character( 873 self, 874 member_id: int, 875 membership_type: typedefs.IntAnd[enums.MembershipType], 876 character_id: int, 877 components: list[enums.ComponentType], 878 auth: typing.Optional[str] = None, 879 ) -> typedefs.JSONObject: 880 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 881 collector = _collect_components(components) 882 response = await self._request( 883 RequestMethod.GET, 884 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 885 f"Character/{character_id}/?components={collector}", 886 auth=auth, 887 ) 888 assert isinstance(response, dict) 889 return response 890 891 async def fetch_activities( 892 self, 893 member_id: int, 894 character_id: int, 895 mode: typedefs.IntAnd[enums.GameMode], 896 membership_type: typedefs.IntAnd[ 897 enums.MembershipType 898 ] = enums.MembershipType.ALL, 899 *, 900 page: int = 0, 901 limit: int = 1, 902 ) -> typedefs.JSONObject: 903 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 904 resp = await self._request( 905 RequestMethod.GET, 906 f"Destiny2/{int(membership_type)}/Account/" 907 f"{member_id}/Character/{character_id}/Stats/Activities" 908 f"/?mode={int(mode)}&count={limit}&page={page}", 909 ) 910 assert isinstance(resp, dict) 911 return resp 912 913 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 914 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 915 resp = await self._request( 916 RequestMethod.GET, 917 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 918 ) 919 assert isinstance(resp, dict) 920 return resp 921 922 async def fetch_profile( 923 self, 924 membership_id: int, 925 type: typedefs.IntAnd[enums.MembershipType], 926 components: list[enums.ComponentType], 927 auth: typing.Optional[str] = None, 928 ) -> typedefs.JSONObject: 929 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 930 collector = _collect_components(components) 931 response = await self._request( 932 RequestMethod.GET, 933 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 934 auth=auth, 935 ) 936 assert isinstance(response, dict) 937 return response 938 939 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 940 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 941 response = await self._request( 942 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 943 ) 944 assert isinstance(response, dict) 945 return response 946 947 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 948 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 949 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 950 assert isinstance(resp, dict) 951 return resp 952 953 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 954 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 955 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 956 assert isinstance(resp, dict) 957 return resp 958 959 async def fetch_groups_for_member( 960 self, 961 member_id: int, 962 member_type: typedefs.IntAnd[enums.MembershipType], 963 /, 964 *, 965 filter: int = 0, 966 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 967 ) -> typedefs.JSONObject: 968 resp = await self._request( 969 RequestMethod.GET, 970 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 971 ) 972 assert isinstance(resp, dict) 973 return resp 974 975 async def fetch_potential_groups_for_member( 976 self, 977 member_id: int, 978 member_type: typedefs.IntAnd[enums.MembershipType], 979 /, 980 *, 981 filter: int = 0, 982 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 983 ) -> typedefs.JSONObject: 984 resp = await self._request( 985 RequestMethod.GET, 986 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 987 ) 988 assert isinstance(resp, dict) 989 return resp 990 991 async def fetch_clan_members( 992 self, 993 clan_id: int, 994 /, 995 *, 996 name: typing.Optional[str] = None, 997 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 998 ) -> typedefs.JSONObject: 999 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1000 resp = await self._request( 1001 RequestMethod.GET, 1002 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 1003 ) 1004 assert isinstance(resp, dict) 1005 return resp 1006 1007 async def fetch_hardlinked_credentials( 1008 self, 1009 credential: int, 1010 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1011 /, 1012 ) -> typedefs.JSONObject: 1013 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1014 resp = await self._request( 1015 RequestMethod.GET, 1016 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1017 ) 1018 assert isinstance(resp, dict) 1019 return resp 1020 1021 async def fetch_user_credentials( 1022 self, access_token: str, membership_id: int, / 1023 ) -> typedefs.JSONArray: 1024 resp = await self._request( 1025 RequestMethod.GET, 1026 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1027 auth=access_token, 1028 ) 1029 assert isinstance(resp, list) 1030 return resp 1031 1032 async def insert_socket_plug( 1033 self, 1034 action_token: str, 1035 /, 1036 instance_id: int, 1037 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1038 character_id: int, 1039 membership_type: typedefs.IntAnd[enums.MembershipType], 1040 ) -> typedefs.JSONObject: 1041 1042 if isinstance(plug, builders.PlugSocketBuilder): 1043 plug = plug.collect() 1044 1045 body = { 1046 "actionToken": action_token, 1047 "itemInstanceId": instance_id, 1048 "plug": plug, 1049 "characterId": character_id, 1050 "membershipType": int(membership_type), 1051 } 1052 resp = await self._request( 1053 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1054 ) 1055 assert isinstance(resp, dict) 1056 return resp 1057 1058 async def insert_socket_plug_free( 1059 self, 1060 access_token: str, 1061 /, 1062 instance_id: int, 1063 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1064 character_id: int, 1065 membership_type: typedefs.IntAnd[enums.MembershipType], 1066 ) -> typedefs.JSONObject: 1067 1068 if isinstance(plug, builders.PlugSocketBuilder): 1069 plug = plug.collect() 1070 1071 body = { 1072 "itemInstanceId": instance_id, 1073 "plug": plug, 1074 "characterId": character_id, 1075 "membershipType": int(membership_type), 1076 } 1077 resp = await self._request( 1078 RequestMethod.POST, 1079 "Destiny2/Actions/Items/InsertSocketPlugFree", 1080 json=body, 1081 auth=access_token, 1082 ) 1083 assert isinstance(resp, dict) 1084 return resp 1085 1086 async def set_item_lock_state( 1087 self, 1088 access_token: str, 1089 state: bool, 1090 /, 1091 item_id: int, 1092 character_id: int, 1093 membership_type: typedefs.IntAnd[enums.MembershipType], 1094 ) -> int: 1095 body = { 1096 "state": state, 1097 "itemId": item_id, 1098 "characterId": character_id, 1099 "membership_type": int(membership_type), 1100 } 1101 response = await self._request( 1102 RequestMethod.POST, 1103 "Destiny2/Actions/Items/SetLockState", 1104 json=body, 1105 auth=access_token, 1106 ) 1107 assert isinstance(response, int) 1108 return response 1109 1110 async def set_quest_track_state( 1111 self, 1112 access_token: str, 1113 state: bool, 1114 /, 1115 item_id: int, 1116 character_id: int, 1117 membership_type: typedefs.IntAnd[enums.MembershipType], 1118 ) -> int: 1119 body = { 1120 "state": state, 1121 "itemId": item_id, 1122 "characterId": character_id, 1123 "membership_type": int(membership_type), 1124 } 1125 response = await self._request( 1126 RequestMethod.POST, 1127 "Destiny2/Actions/Items/SetTrackedState", 1128 json=body, 1129 auth=access_token, 1130 ) 1131 assert isinstance(response, int) 1132 return response 1133 1134 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1135 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1136 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1137 assert isinstance(path, dict) 1138 return path 1139 1140 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1141 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1142 _ensure_manifest_language(language) 1143 1144 content = await self.fetch_manifest_path() 1145 resp = await self._request( 1146 RequestMethod.GET, 1147 content["mobileWorldContentPaths"][language], 1148 unwrapping="read", 1149 base=True, 1150 ) 1151 assert isinstance(resp, bytes) 1152 return resp 1153 1154 async def download_manifest( 1155 self, 1156 language: str = "en", 1157 name: str = "manifest", 1158 path: typing.Union[pathlib.Path, str] = ".", 1159 *, 1160 force: bool = False, 1161 ) -> None: 1162 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1163 complete_path = _get_path(name, path, sql=True) 1164 1165 if complete_path.exists() and force: 1166 if force: 1167 _LOG.info( 1168 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1169 ) 1170 complete_path.unlink(missing_ok=True) 1171 1172 return await self.download_manifest(language, name, path, force=force) 1173 1174 else: 1175 raise FileExistsError( 1176 "Manifest file already exists, " 1177 "To force download, set the `force` parameter to `True`." 1178 ) 1179 1180 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1181 data_bytes = await self.read_manifest_bytes(language) 1182 await asyncio.get_running_loop().run_in_executor( 1183 None, _write_sqlite_bytes, data_bytes, path, name 1184 ) 1185 1186 async def download_json_manifest( 1187 self, 1188 file_name: str = "manifest", 1189 path: typing.Union[str, pathlib.Path] = ".", 1190 language: str = "en", 1191 ) -> None: 1192 _ensure_manifest_language(language) 1193 1194 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1195 1196 content = await self.fetch_manifest_path() 1197 json_bytes = await self._request( 1198 RequestMethod.GET, 1199 content["jsonWorldContentPaths"][language], 1200 unwrapping="read", 1201 base=True, 1202 ) 1203 1204 await asyncio.get_running_loop().run_in_executor( 1205 None, _write_json_bytes, json_bytes, file_name, path 1206 ) 1207 _LOG.info("Finished downloading manifest JSON.") 1208 1209 async def fetch_manifest_version(self) -> str: 1210 return typing.cast(str, (await self.fetch_manifest_path())["version"]) 1211 1212 async def fetch_linked_profiles( 1213 self, 1214 member_id: int, 1215 member_type: typedefs.IntAnd[enums.MembershipType], 1216 /, 1217 *, 1218 all: bool = False, 1219 ) -> typedefs.JSONObject: 1220 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1221 resp = await self._request( 1222 RequestMethod.GET, 1223 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1224 ) 1225 assert isinstance(resp, dict) 1226 return resp 1227 1228 async def fetch_clan_banners(self) -> typedefs.JSONObject: 1229 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1230 resp = await self._request( 1231 RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/" 1232 ) 1233 assert isinstance(resp, dict) 1234 return resp 1235 1236 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1237 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1238 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1239 assert isinstance(resp, dict) 1240 return resp 1241 1242 async def fetch_public_milestone_content( 1243 self, milestone_hash: int, / 1244 ) -> typedefs.JSONObject: 1245 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1246 resp = await self._request( 1247 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp 1251 1252 async def fetch_current_user_memberships( 1253 self, access_token: str, / 1254 ) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request( 1257 RequestMethod.GET, 1258 "User/GetMembershipsForCurrentUser/", 1259 auth=access_token, 1260 ) 1261 assert isinstance(resp, dict) 1262 return resp 1263 1264 async def equip_item( 1265 self, 1266 access_token: str, 1267 /, 1268 item_id: int, 1269 character_id: int, 1270 membership_type: typedefs.IntAnd[enums.MembershipType], 1271 ) -> None: 1272 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1273 payload = { 1274 "itemId": item_id, 1275 "characterId": character_id, 1276 "membershipType": int(membership_type), 1277 } 1278 1279 await self._request( 1280 RequestMethod.POST, 1281 "Destiny2/Actions/Items/EquipItem/", 1282 json=payload, 1283 auth=access_token, 1284 ) 1285 1286 async def equip_items( 1287 self, 1288 access_token: str, 1289 /, 1290 item_ids: list[int], 1291 character_id: int, 1292 membership_type: typedefs.IntAnd[enums.MembershipType], 1293 ) -> None: 1294 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1295 payload = { 1296 "itemIds": item_ids, 1297 "characterId": character_id, 1298 "membershipType": int(membership_type), 1299 } 1300 await self._request( 1301 RequestMethod.POST, 1302 "Destiny2/Actions/Items/EquipItems/", 1303 json=payload, 1304 auth=access_token, 1305 ) 1306 1307 async def ban_clan_member( 1308 self, 1309 access_token: str, 1310 /, 1311 group_id: int, 1312 membership_id: int, 1313 membership_type: typedefs.IntAnd[enums.MembershipType], 1314 *, 1315 length: int = 0, 1316 comment: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1317 ) -> None: 1318 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1319 payload = {"comment": str(comment), "length": length} 1320 await self._request( 1321 RequestMethod.POST, 1322 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1323 json=payload, 1324 auth=access_token, 1325 ) 1326 1327 async def unban_clan_member( 1328 self, 1329 access_token: str, 1330 /, 1331 group_id: int, 1332 membership_id: int, 1333 membership_type: typedefs.IntAnd[enums.MembershipType], 1334 ) -> None: 1335 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1336 await self._request( 1337 RequestMethod.POST, 1338 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1339 auth=access_token, 1340 ) 1341 1342 async def kick_clan_member( 1343 self, 1344 access_token: str, 1345 /, 1346 group_id: int, 1347 membership_id: int, 1348 membership_type: typedefs.IntAnd[enums.MembershipType], 1349 ) -> typedefs.JSONObject: 1350 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1351 resp = await self._request( 1352 RequestMethod.POST, 1353 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1354 auth=access_token, 1355 ) 1356 assert isinstance(resp, dict) 1357 return resp 1358 1359 async def edit_clan( 1360 self, 1361 access_token: str, 1362 /, 1363 group_id: int, 1364 *, 1365 name: typedefs.NoneOr[str] = None, 1366 about: typedefs.NoneOr[str] = None, 1367 motto: typedefs.NoneOr[str] = None, 1368 theme: typedefs.NoneOr[str] = None, 1369 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1370 is_public: typedefs.NoneOr[bool] = None, 1371 locale: typedefs.NoneOr[str] = None, 1372 avatar_image_index: typedefs.NoneOr[int] = None, 1373 membership_option: typedefs.NoneOr[ 1374 typedefs.IntAnd[enums.MembershipOption] 1375 ] = None, 1376 allow_chat: typedefs.NoneOr[bool] = None, 1377 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1378 call_sign: typedefs.NoneOr[str] = None, 1379 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1380 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1381 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1382 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1383 ) -> None: 1384 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1385 payload = { 1386 "name": name, 1387 "about": about, 1388 "motto": motto, 1389 "theme": theme, 1390 "tags": tags, 1391 "isPublic": is_public, 1392 "avatarImageIndex": avatar_image_index, 1393 "isPublicTopicAdminOnly": is_public_topic_admin, 1394 "allowChat": allow_chat, 1395 "chatSecurity": chat_security, 1396 "callsign": call_sign, 1397 "homepage": homepage, 1398 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1399 "defaultPublicity": default_publicity, 1400 "locale": locale, 1401 } 1402 if membership_option is not None: 1403 payload["membershipOption"] = int(membership_option) 1404 1405 await self._request( 1406 RequestMethod.POST, 1407 f"GroupV2/{group_id}/Edit", 1408 json=payload, 1409 auth=access_token, 1410 ) 1411 1412 async def edit_clan_options( 1413 self, 1414 access_token: str, 1415 /, 1416 group_id: int, 1417 *, 1418 invite_permissions_override: typedefs.NoneOr[bool] = None, 1419 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1420 host_guided_game_permission_override: typedefs.NoneOr[ 1421 typing.Literal[0, 1, 2] 1422 ] = None, 1423 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1424 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1425 ) -> None: 1426 1427 payload = { 1428 "InvitePermissionOverride": invite_permissions_override, 1429 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1430 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1431 "UpdateBannerPermissionOverride": update_banner_permission_override, 1432 "JoinLevel": int(join_level) if join_level else None, 1433 } 1434 1435 await self._request( 1436 RequestMethod.POST, 1437 f"GroupV2/{group_id}/EditFounderOptions", 1438 json=payload, 1439 auth=access_token, 1440 ) 1441 1442 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1443 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1444 resp = await self._request( 1445 RequestMethod.GET, 1446 "Social/Friends/", 1447 auth=access_token, 1448 ) 1449 assert isinstance(resp, dict) 1450 return resp 1451 1452 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1453 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1454 resp = await self._request( 1455 RequestMethod.GET, 1456 "Social/Friends/Requests", 1457 auth=access_token, 1458 ) 1459 assert isinstance(resp, dict) 1460 return resp 1461 1462 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1463 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1464 await self._request( 1465 RequestMethod.POST, 1466 f"Social/Friends/Requests/Accept/{member_id}", 1467 auth=access_token, 1468 ) 1469 1470 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 await self._request( 1473 RequestMethod.POST, 1474 f"Social/Friends/Add/{member_id}", 1475 auth=access_token, 1476 ) 1477 1478 async def decline_friend_request( 1479 self, access_token: str, /, member_id: int 1480 ) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Decline/{member_id}", 1485 auth=access_token, 1486 ) 1487 1488 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Remove/{member_id}", 1493 auth=access_token, 1494 ) 1495 1496 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1497 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1498 await self._request( 1499 RequestMethod.POST, 1500 f"Social/Friends/Requests/Remove/{member_id}", 1501 auth=access_token, 1502 ) 1503 1504 async def approve_all_pending_group_users( 1505 self, 1506 access_token: str, 1507 /, 1508 group_id: int, 1509 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1510 ) -> None: 1511 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1512 await self._request( 1513 RequestMethod.POST, 1514 f"GroupV2/{group_id}/Members/ApproveAll", 1515 auth=access_token, 1516 json={"message": str(message)}, 1517 ) 1518 1519 async def deny_all_pending_group_users( 1520 self, 1521 access_token: str, 1522 /, 1523 group_id: int, 1524 *, 1525 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1526 ) -> None: 1527 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1528 await self._request( 1529 RequestMethod.POST, 1530 f"GroupV2/{group_id}/Members/DenyAll", 1531 auth=access_token, 1532 json={"message": str(message)}, 1533 ) 1534 1535 async def add_optional_conversation( 1536 self, 1537 access_token: str, 1538 /, 1539 group_id: int, 1540 *, 1541 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1542 security: typing.Literal[0, 1] = 0, 1543 ) -> None: 1544 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1545 payload = {"chatName": str(name), "chatSecurity": security} 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/OptionalConversations/Add", 1549 json=payload, 1550 auth=access_token, 1551 ) 1552 1553 async def edit_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 conversation_id: int, 1559 *, 1560 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1561 security: typing.Literal[0, 1] = 0, 1562 enable_chat: bool = False, 1563 ) -> None: 1564 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1565 payload = { 1566 "chatEnabled": enable_chat, 1567 "chatName": str(name), 1568 "chatSecurity": security, 1569 } 1570 await self._request( 1571 RequestMethod.POST, 1572 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1573 json=payload, 1574 auth=access_token, 1575 ) 1576 1577 async def transfer_item( 1578 self, 1579 access_token: str, 1580 /, 1581 item_id: int, 1582 item_hash: int, 1583 character_id: int, 1584 member_type: typedefs.IntAnd[enums.MembershipType], 1585 *, 1586 stack_size: int = 1, 1587 vault: bool = False, 1588 ) -> None: 1589 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1590 payload = { 1591 "characterId": character_id, 1592 "membershipType": int(member_type), 1593 "itemId": item_id, 1594 "itemReferenceHash": item_hash, 1595 "stackSize": stack_size, 1596 "transferToVault": vault, 1597 } 1598 await self._request( 1599 RequestMethod.POST, 1600 "Destiny2/Actions/Items/TransferItem", 1601 json=payload, 1602 auth=access_token, 1603 ) 1604 1605 async def pull_item( 1606 self, 1607 access_token: str, 1608 /, 1609 item_id: int, 1610 item_hash: int, 1611 character_id: int, 1612 member_type: typedefs.IntAnd[enums.MembershipType], 1613 *, 1614 stack_size: int = 1, 1615 vault: bool = False, 1616 ) -> None: 1617 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1618 payload = { 1619 "characterId": character_id, 1620 "membershipType": int(member_type), 1621 "itemId": item_id, 1622 "itemReferenceHash": item_hash, 1623 "stackSize": stack_size, 1624 "transferToVault": vault, 1625 } 1626 await self._request( 1627 RequestMethod.POST, 1628 "Destiny2/Actions/Items/PullFromPostmaster", 1629 json=payload, 1630 auth=access_token, 1631 ) 1632 1633 async def fetch_fireteams( 1634 self, 1635 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1636 *, 1637 platform: typedefs.IntAnd[ 1638 fireteams.FireteamPlatform 1639 ] = fireteams.FireteamPlatform.ANY, 1640 language: typing.Union[ 1641 fireteams.FireteamLanguage, str 1642 ] = fireteams.FireteamLanguage.ALL, 1643 date_range: typedefs.IntAnd[ 1644 fireteams.FireteamDate 1645 ] = fireteams.FireteamDate.ALL, 1646 page: int = 0, 1647 slots_filter: int = 0, 1648 ) -> typedefs.JSONObject: 1649 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1650 resp = await self._request( 1651 RequestMethod.GET, 1652 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1653 ) 1654 assert isinstance(resp, dict) 1655 return resp 1656 1657 async def fetch_avaliable_clan_fireteams( 1658 self, 1659 access_token: str, 1660 group_id: int, 1661 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1662 *, 1663 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1664 language: typing.Union[fireteams.FireteamLanguage, str], 1665 date_range: typedefs.IntAnd[ 1666 fireteams.FireteamDate 1667 ] = fireteams.FireteamDate.ALL, 1668 page: int = 0, 1669 public_only: bool = False, 1670 slots_filter: int = 0, 1671 ) -> typedefs.JSONObject: 1672 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1673 resp = await self._request( 1674 RequestMethod.GET, 1675 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1676 json={"langFilter": str(language)}, 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp 1681 1682 async def fetch_clan_fireteam( 1683 self, access_token: str, fireteam_id: int, group_id: int 1684 ) -> typedefs.JSONObject: 1685 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1686 resp = await self._request( 1687 RequestMethod.GET, 1688 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1689 auth=access_token, 1690 ) 1691 assert isinstance(resp, dict) 1692 return resp 1693 1694 async def fetch_my_clan_fireteams( 1695 self, 1696 access_token: str, 1697 group_id: int, 1698 *, 1699 include_closed: bool = True, 1700 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1701 language: typing.Union[fireteams.FireteamLanguage, str], 1702 filtered: bool = True, 1703 page: int = 0, 1704 ) -> typedefs.JSONObject: 1705 payload = {"groupFilter": filtered, "langFilter": str(language)} 1706 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1707 resp = await self._request( 1708 RequestMethod.GET, 1709 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1710 json=payload, 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, dict) 1714 return resp 1715 1716 async def fetch_private_clan_fireteams( 1717 self, access_token: str, group_id: int, / 1718 ) -> int: 1719 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1720 resp = await self._request( 1721 RequestMethod.GET, 1722 f"Fireteam/Clan/{group_id}/ActiveCount", 1723 auth=access_token, 1724 ) 1725 assert isinstance(resp, int) 1726 return resp 1727 1728 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1729 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1730 resp = await self._request( 1731 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp 1735 1736 async def search_entities( 1737 self, name: str, entity_type: str, *, page: int = 0 1738 ) -> typedefs.JSONObject: 1739 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1740 resp = await self._request( 1741 RequestMethod.GET, 1742 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1743 json={"page": page}, 1744 ) 1745 assert isinstance(resp, dict) 1746 return resp 1747 1748 async def fetch_unique_weapon_history( 1749 self, 1750 membership_id: int, 1751 character_id: int, 1752 membership_type: typedefs.IntAnd[enums.MembershipType], 1753 ) -> typedefs.JSONObject: 1754 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1758 ) 1759 assert isinstance(resp, dict) 1760 return resp 1761 1762 async def fetch_item( 1763 self, 1764 member_id: int, 1765 item_id: int, 1766 membership_type: typedefs.IntAnd[enums.MembershipType], 1767 components: list[enums.ComponentType], 1768 ) -> typedefs.JSONObject: 1769 collector = _collect_components(components) 1770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1771 resp = await self._request( 1772 RequestMethod.GET, 1773 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1774 ) 1775 assert isinstance(resp, dict) 1776 return resp 1777 1778 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1779 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1780 resp = await self._request( 1781 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1782 ) 1783 assert isinstance(resp, dict) 1784 return resp 1785 1786 async def fetch_available_locales(self) -> typedefs.JSONObject: 1787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1788 resp = await self._request( 1789 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1790 ) 1791 assert isinstance(resp, dict) 1792 return resp 1793 1794 async def fetch_common_settings(self) -> typedefs.JSONObject: 1795 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1796 resp = await self._request(RequestMethod.GET, "Settings") 1797 assert isinstance(resp, dict) 1798 return resp 1799 1800 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1802 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1803 assert isinstance(resp, dict) 1804 return resp 1805 1806 async def fetch_global_alerts( 1807 self, *, include_streaming: bool = False 1808 ) -> typedefs.JSONArray: 1809 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1810 resp = await self._request( 1811 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1812 ) 1813 assert isinstance(resp, list) 1814 return resp 1815 1816 async def awainitialize_request( 1817 self, 1818 access_token: str, 1819 type: typing.Literal[0, 1], 1820 membership_type: typedefs.IntAnd[enums.MembershipType], 1821 /, 1822 *, 1823 affected_item_id: typing.Optional[int] = None, 1824 character_id: typing.Optional[int] = None, 1825 ) -> typedefs.JSONObject: 1826 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1827 1828 body = {"type": type, "membershipType": int(membership_type)} 1829 1830 if affected_item_id is not None: 1831 body["affectedItemId"] = affected_item_id 1832 1833 if character_id is not None: 1834 body["characterId"] = character_id 1835 1836 resp = await self._request( 1837 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp 1841 1842 async def awaget_action_token( 1843 self, access_token: str, correlation_id: str, / 1844 ) -> typedefs.JSONObject: 1845 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1846 resp = await self._request( 1847 RequestMethod.POST, 1848 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1849 auth=access_token, 1850 ) 1851 assert isinstance(resp, dict) 1852 return resp 1853 1854 async def awa_provide_authorization_result( 1855 self, 1856 access_token: str, 1857 selection: int, 1858 correlation_id: str, 1859 nonce: collections.MutableSequence[typing.Union[str, bytes]], 1860 ) -> int: 1861 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1862 1863 body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce} 1864 1865 resp = await self._request( 1866 RequestMethod.POST, 1867 "Destiny2/Awa/AwaProvideAuthorizationResult", 1868 json=body, 1869 auth=access_token, 1870 ) 1871 assert isinstance(resp, int) 1872 return resp 1873 1874 async def fetch_vendors( 1875 self, 1876 access_token: str, 1877 character_id: int, 1878 membership_id: int, 1879 membership_type: typedefs.IntAnd[enums.MembershipType], 1880 /, 1881 components: list[enums.ComponentType], 1882 filter: typing.Optional[int] = None, 1883 ) -> typedefs.JSONObject: 1884 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1885 components_ = _collect_components(components) 1886 route = ( 1887 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1888 f"/Character/{character_id}/Vendors/?components={components_}" 1889 ) 1890 1891 if filter is not None: 1892 route = route + f"&filter={filter}" 1893 1894 resp = await self._request( 1895 RequestMethod.GET, 1896 route, 1897 auth=access_token, 1898 ) 1899 assert isinstance(resp, dict) 1900 return resp 1901 1902 async def fetch_vendor( 1903 self, 1904 access_token: str, 1905 character_id: int, 1906 membership_id: int, 1907 membership_type: typedefs.IntAnd[enums.MembershipType], 1908 vendor_hash: int, 1909 /, 1910 components: list[enums.ComponentType], 1911 ) -> typedefs.JSONObject: 1912 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1913 components_ = _collect_components(components) 1914 resp = await self._request( 1915 RequestMethod.GET, 1916 ( 1917 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1918 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1919 ), 1920 auth=access_token, 1921 ) 1922 assert isinstance(resp, dict) 1923 return resp 1924 1925 async def fetch_application_api_usage( 1926 self, 1927 access_token: str, 1928 application_id: int, 1929 /, 1930 *, 1931 start: typing.Optional[datetime.datetime] = None, 1932 end: typing.Optional[datetime.datetime] = None, 1933 ) -> typedefs.JSONObject: 1934 1935 end_date, start_date = time.parse_date_range(end, start) 1936 resp = await self._request( 1937 RequestMethod.GET, 1938 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1939 auth=access_token, 1940 ) 1941 assert isinstance(resp, dict) 1942 return resp 1943 1944 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1945 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1946 assert isinstance(resp, list) 1947 return resp 1948 1949 async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject: 1950 resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/") 1951 assert isinstance(resp, dict) 1952 return resp 1953 1954 async def fetch_content_by_id( 1955 self, id: int, locale: str, /, *, head: bool = False 1956 ) -> typedefs.JSONObject: 1957 resp = await self._request( 1958 RequestMethod.GET, 1959 f"Content/GetContentById/{id}/{locale}/", 1960 json={"head": head}, 1961 ) 1962 assert isinstance(resp, dict) 1963 return resp 1964 1965 async def fetch_content_by_tag_and_type( 1966 self, locale: str, tag: str, type: str, *, head: bool = False 1967 ) -> typedefs.JSONObject: 1968 resp = await self._request( 1969 RequestMethod.GET, 1970 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1971 json={"head": head}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp 1975 1976 async def search_content_with_text( 1977 self, 1978 locale: str, 1979 /, 1980 content_type: str, 1981 search_text: str, 1982 tag: str, 1983 *, 1984 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1985 source: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1986 ) -> typedefs.JSONObject: 1987 1988 body: typedefs.JSONObject = {} 1989 1990 body["ctype"] = content_type 1991 body["searchtext"] = search_text 1992 body["tag"] = tag 1993 1994 if page is not undefined.UNDEFINED: 1995 body["currentpage"] = page 1996 else: 1997 body["currentpage"] = 1 1998 1999 if source is not undefined.UNDEFINED: 2000 body["source"] = source 2001 else: 2002 source = "" 2003 resp = await self._request( 2004 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2005 ) 2006 assert isinstance(resp, dict) 2007 return resp 2008 2009 async def search_content_by_tag_and_type( 2010 self, 2011 locale: str, 2012 tag: str, 2013 type: str, 2014 *, 2015 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 2016 ) -> typedefs.JSONObject: 2017 body: typedefs.JSONObject = {} 2018 body["currentpage"] = 1 if page is undefined.UNDEFINED else page 2019 resp = await self._request( 2020 RequestMethod.GET, 2021 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2022 json=body, 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp 2026 2027 async def search_help_articles( 2028 self, text: str, size: str, / 2029 ) -> typedefs.JSONObject: 2030 resp = await self._request( 2031 RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/" 2032 ) 2033 assert isinstance(resp, dict) 2034 return resp 2035 2036 async def fetch_topics_page( 2037 self, 2038 category_filter: int, 2039 group: int, 2040 date_filter: int, 2041 sort: typing.Union[str, bytes], 2042 *, 2043 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 2044 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 2045 tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED, 2046 ) -> typedefs.JSONObject: 2047 2048 body: typedefs.JSONObject = {} 2049 if locales is not undefined.UNDEFINED: 2050 body["locales"] = ",".join(str(locales)) 2051 else: 2052 body["locales"] = ",".join([]) 2053 2054 if tag_filter is not undefined.UNDEFINED: 2055 body["tagstring"] = tag_filter 2056 else: 2057 body["tagstring"] = "" 2058 2059 page = 0 if page is not undefined.UNDEFINED else page 2060 2061 resp = await self._request( 2062 RequestMethod.GET, 2063 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2064 json=body, 2065 ) 2066 assert isinstance(resp, dict) 2067 return resp 2068 2069 async def fetch_core_topics_page( 2070 self, 2071 category_filter: int, 2072 date_filter: int, 2073 sort: typing.Union[str, bytes], 2074 *, 2075 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 2076 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 2077 ) -> typedefs.JSONObject: 2078 body: typedefs.JSONObject = {} 2079 2080 if locales is not undefined.UNDEFINED: 2081 body["locales"] = ",".join(str(locales)) 2082 else: 2083 body["locales"] = ",".join([]) 2084 2085 resp = await self._request( 2086 RequestMethod.GET, 2087 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}" 2088 f"/{sort!s}/{date_filter}/{category_filter}/", 2089 json=body, 2090 ) 2091 assert isinstance(resp, dict) 2092 return resp 2093 2094 async def fetch_posts_threaded_page( 2095 self, 2096 parent_post: bool, 2097 page: int, 2098 page_size: int, 2099 parent_post_id: int, 2100 reply_size: int, 2101 root_thread_mode: bool, 2102 sort_mode: int, 2103 show_banned: typing.Optional[str] = None, 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2108 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2109 json={"showbanned": show_banned}, 2110 ) 2111 assert isinstance(resp, dict) 2112 return resp 2113 2114 async def fetch_posts_threaded_page_from_child( 2115 self, 2116 child_id: bool, 2117 page: int, 2118 page_size: int, 2119 reply_size: int, 2120 root_thread_mode: bool, 2121 sort_mode: int, 2122 show_banned: typing.Optional[str] = None, 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2127 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2128 json={"showbanned": show_banned}, 2129 ) 2130 assert isinstance(resp, dict) 2131 return resp 2132 2133 async def fetch_post_and_parent( 2134 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2135 ) -> typedefs.JSONObject: 2136 resp = await self._request( 2137 RequestMethod.GET, 2138 f"Forum/GetPostAndParent/{child_id}/", 2139 json={"showbanned": show_banned}, 2140 ) 2141 assert isinstance(resp, dict) 2142 return resp 2143 2144 async def fetch_posts_and_parent_awaiting( 2145 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2146 ) -> typedefs.JSONObject: 2147 resp = await self._request( 2148 RequestMethod.GET, 2149 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2150 json={"showbanned": show_banned}, 2151 ) 2152 assert isinstance(resp, dict) 2153 return resp 2154 2155 async def fetch_topic_for_content(self, content_id: int, /) -> int: 2156 resp = await self._request( 2157 RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/" 2158 ) 2159 assert isinstance(resp, int) 2160 return resp 2161 2162 async def fetch_forum_tag_suggestions( 2163 self, partial_tag: str, / 2164 ) -> typedefs.JSONObject: 2165 resp = await self._request( 2166 RequestMethod.GET, 2167 "Forum/GetForumTagSuggestions/", 2168 json={"partialtag": partial_tag}, 2169 ) 2170 assert isinstance(resp, dict) 2171 return resp 2172 2173 async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject: 2174 resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/") 2175 assert isinstance(resp, dict) 2176 return resp 2177 2178 async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray: 2179 resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/") 2180 assert isinstance(resp, list) 2181 return resp 2182 2183 async def fetch_recommended_groups( 2184 self, 2185 accecss_token: str, 2186 /, 2187 *, 2188 date_range: int = 0, 2189 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2190 ) -> typedefs.JSONArray: 2191 resp = await self._request( 2192 RequestMethod.POST, 2193 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2194 auth=accecss_token, 2195 ) 2196 assert isinstance(resp, list) 2197 return resp 2198 2199 async def fetch_available_avatars(self) -> collections.Mapping[str, int]: 2200 resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/") 2201 assert isinstance(resp, dict) 2202 return resp 2203 2204 async def fetch_user_clan_invite_setting( 2205 self, 2206 access_token: str, 2207 /, 2208 membership_type: typedefs.IntAnd[enums.MembershipType], 2209 ) -> bool: 2210 resp = await self._request( 2211 RequestMethod.GET, 2212 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2213 auth=access_token, 2214 ) 2215 assert isinstance(resp, bool) 2216 return resp 2217 2218 async def fetch_banned_group_members( 2219 self, access_token: str, group_id: int, /, *, page: int = 1 2220 ) -> typedefs.JSONObject: 2221 resp = await self._request( 2222 RequestMethod.GET, 2223 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2224 auth=access_token, 2225 ) 2226 assert isinstance(resp, dict) 2227 return resp 2228 2229 async def fetch_pending_group_memberships( 2230 self, access_token: str, group_id: int, /, *, current_page: int = 1 2231 ) -> typedefs.JSONObject: 2232 resp = await self._request( 2233 RequestMethod.GET, 2234 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2235 auth=access_token, 2236 ) 2237 assert isinstance(resp, dict) 2238 return resp 2239 2240 async def fetch_invited_group_memberships( 2241 self, access_token: str, group_id: int, /, *, current_page: int = 1 2242 ) -> typedefs.JSONObject: 2243 resp = await self._request( 2244 RequestMethod.GET, 2245 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2246 auth=access_token, 2247 ) 2248 assert isinstance(resp, dict) 2249 return resp 2250 2251 async def invite_member_to_group( 2252 self, 2253 access_token: str, 2254 /, 2255 group_id: int, 2256 membership_id: int, 2257 membership_type: typedefs.IntAnd[enums.MembershipType], 2258 *, 2259 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.POST, 2263 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2264 auth=access_token, 2265 json={"message": str(message)}, 2266 ) 2267 assert isinstance(resp, dict) 2268 return resp 2269 2270 async def cancel_group_member_invite( 2271 self, 2272 access_token: str, 2273 /, 2274 group_id: int, 2275 membership_id: int, 2276 membership_type: typedefs.IntAnd[enums.MembershipType], 2277 ) -> typedefs.JSONObject: 2278 resp = await self._request( 2279 RequestMethod.POST, 2280 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2281 auth=access_token, 2282 ) 2283 assert isinstance(resp, dict) 2284 return resp 2285 2286 async def fetch_historical_definition(self) -> typedefs.JSONObject: 2287 resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/") 2288 assert isinstance(resp, dict) 2289 return resp 2290 2291 async def fetch_historical_stats( 2292 self, 2293 character_id: int, 2294 membership_id: int, 2295 membership_type: typedefs.IntAnd[enums.MembershipType], 2296 day_start: datetime.datetime, 2297 day_end: datetime.datetime, 2298 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2299 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2300 *, 2301 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2302 ) -> typedefs.JSONObject: 2303 2304 end, start = time.parse_date_range(day_end, day_start) 2305 resp = await self._request( 2306 RequestMethod.GET, 2307 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2308 json={ 2309 "dayend": end, 2310 "daystart": start, 2311 "groups": [str(int(group)) for group in groups], 2312 "modes": [str(int(mode)) for mode in modes], 2313 "periodType": int(period_type), 2314 }, 2315 ) 2316 assert isinstance(resp, dict) 2317 return resp 2318 2319 async def fetch_historical_stats_for_account( 2320 self, 2321 membership_id: int, 2322 membership_type: typedefs.IntAnd[enums.MembershipType], 2323 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2324 ) -> typedefs.JSONObject: 2325 resp = await self._request( 2326 RequestMethod.GET, 2327 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2328 json={"groups": [str(int(group)) for group in groups]}, 2329 ) 2330 assert isinstance(resp, dict) 2331 return resp 2332 2333 async def fetch_aggregated_activity_stats( 2334 self, 2335 character_id: int, 2336 membership_id: int, 2337 membership_type: typedefs.IntAnd[enums.MembershipType], 2338 /, 2339 ) -> typedefs.JSONObject: 2340 resp = await self._request( 2341 RequestMethod.GET, 2342 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2343 f"Character/{character_id}/Stats/AggregateActivityStats/", 2344 ) 2345 assert isinstance(resp, dict) 2346 return resp
A RESTful client implementation for Bungie's API.
This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.
This client is also used within aiobungie.Client which deserialize those returned JSON objects
using the factory into Pythonic data classes objects which provide Python functionality.
Example
import aiobungie
async def main():
async with aiobungie.RESTClient("TOKEN") as rest_client:
req = await rest_client.fetch_clan_members(4389205)
clan_members = req['results']
for member in clan_members:
for k, v in member['destinyUserInfo'].items():
print(k, v)
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
417 def __init__( 418 self, 419 token: str, 420 /, 421 client_secret: typing.Optional[str] = None, 422 client_id: typing.Optional[int] = None, 423 *, 424 max_retries: int = 4, 425 max_ratelimit_retries: int = 3, 426 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 427 ) -> None: 428 self._session: typing.Optional[_Session] = None 429 self._lock: typing.Optional[asyncio.Lock] = None 430 self._client_secret = client_secret 431 self._client_id = client_id 432 self._token: str = token 433 self._max_retries = max_retries 434 self._max_rate_limit_retries = max_ratelimit_retries 435 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 436 437 self._set_debug_level(enable_debugging)
A mutable mapping storage for the user's needs.
This mapping is useful for storing any kind of data that the user may need.
Example
import aiobungie
client = aiobungie.RESTClient(…)
async with client:
# Fetch auth tokens and store them
client.metadata["tokens"] = await client.fetch_access_token("code")
# Some other time.
async with client:
# Retrieve the tokens
tokens: aiobungie.OAuth2Response = client.metadata["tokens"]
# Use them to fetch your user.
user = await client.fetch_current_user_memberships(tokens.access_token)
451 @typing.final 452 async def close(self) -> None: 453 session = self._get_session() 454 await session.close() 455 self._session = None
Close this REST client session if it was acquired.
This method is automatically called when using async with contextmanager.
Raises
RuntimeError: If the client is already closed.
457 @typing.final 458 def open(self) -> None: 459 """Open a new client session. This is called internally with contextmanager usage.""" 460 if self.is_alive: 461 raise RuntimeError("Cannot open a new session while it's already open.") 462 463 self._session = _Session.create()
Open a new client session. This is called internally with contextmanager usage.
465 @typing.final 466 def enable_debugging( 467 self, 468 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 469 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 470 /, 471 ) -> None: 472 self._set_debug_level(level, file)
Enables debugging for the REST calls.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE"|aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
- level (
str | bool | int): The level of debugging to enable. - file (
pathlib.Path | str | None): The file path to write the debug logs to. If provided.
474 @typing.final 475 async def static_request( 476 self, 477 method: typing.Union[RequestMethod, str], 478 path: str, 479 *, 480 auth: typing.Optional[str] = None, 481 json: typing.Optional[dict[str, typing.Any]] = None, 482 ) -> ResponseSig: 483 return await self._request(method, path, auth=auth, json=json)
Perform an HTTP request given a valid Bungie endpoint.
Parameters
- method (
aiobungie.RequestMethod | str): The request method, This may beGET,POST,PUT, etc. - path (
str): The Bungie endpoint or path. A path must look something like thisDestiny2/3/Profile/46111239123/... - auth (
str | None): An optional bearer token for methods that requires OAuth2 Authorization header. - json (
dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
aiobungie.rest.ResponseSig: The response payload.
485 @typing.final 486 def build_oauth2_url( 487 self, client_id: typing.Optional[int] = None 488 ) -> typing.Optional[builders.OAuthURL]: 489 client_id = client_id or self._client_id 490 if client_id is None: 491 return None 492 493 return builders.OAuthURL(client_id=client_id)
Builds an OAuth2 URL using the provided user REST/Base client secret/id.
You can't get the complete string URL by using .compile() method.
Parameters
- client_id (
int | None): An optional client id to provide, If leftNoneit will roll back to the id passed to theRESTClient, If both isNonethis method will returnNone.
Returns
aiobungie.builders.OAuthURL | None: If the client id was provided as a parameter or provided inaiobungie.RESTClient, A complete OAuthURL object will be returned. OtherwiseNonewill be returned.
720 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 721 722 if not isinstance(self._client_id, int): 723 raise TypeError( 724 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 725 ) 726 727 if not isinstance(self._client_secret, str): 728 raise TypeError( 729 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 730 ) 731 732 headers = { 733 "client_secret": self._client_secret, 734 } 735 736 data = ( 737 f"grant_type=authorization_code&code={code}" 738 f"&client_id={self._client_id}&client_secret={self._client_secret}" 739 ) 740 741 response = await self._request( 742 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 743 ) 744 assert isinstance(response, dict) 745 return builders.OAuth2Response.build_response(response)
Makes a POST request and fetch the OAuth2 access_token and refresh token.
Parameters
- code (
str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
Raises
aiobungie.Unauthorized: The passed code was invalid.
747 async def refresh_access_token( 748 self, refresh_token: str, / 749 ) -> builders.OAuth2Response: 750 if not isinstance(self._client_id, int): 751 raise TypeError( 752 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 753 ) 754 755 if not isinstance(self._client_secret, str): 756 raise TypeError( 757 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 758 ) 759 760 data = { 761 "grant_type": "refresh_token", 762 "refresh_token": refresh_token, 763 "client_id": self._client_id, 764 "client_secret": self._client_secret, 765 "Content-Type": "application/x-www-form-urlencoded", 766 } 767 768 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 769 assert isinstance(response, dict) 770 return builders.OAuth2Response.build_response(response)
Refresh OAuth2 access token given its refresh token.
Parameters
- refresh_token (
str): The refresh token.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
772 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 773 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 774 resp = await self._request( 775 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 776 ) 777 assert isinstance(resp, dict) 778 return resp
Fetch a Bungie user by their id.
Parameters
- id (
int): The user id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of users objects.
Raises
aiobungie.NotFound: The user was not found.
786 async def fetch_membership_from_id( 787 self, 788 id: int, 789 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 790 /, 791 ) -> typedefs.JSONObject: 792 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 793 resp = await self._request( 794 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 795 ) 796 assert isinstance(resp, dict) 797 return resp
Fetch Bungie user's memberships from their id.
Parameters
- id (
int): The user's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user.
Raises
- aiobungie.NotFound: The requested user was not found.
799 async def fetch_player( 800 self, 801 name: str, 802 code: int, 803 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 804 /, 805 ) -> typedefs.JSONArray: 806 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 807 resp = await self._request( 808 RequestMethod.POST, 809 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 810 json={"displayName": name, "displayNameCode": code}, 811 ) 812 assert isinstance(resp, list) 813 return resp
Fetch a Destiny 2 Player.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
aiobungie.typedefs.JSONArray: A JSON array of the found player's memberships.
Raises
aiobungie.NotFound: The player was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
815 async def search_users(self, name: str, /) -> typedefs.JSONObject: 816 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 817 resp = await self._request( 818 RequestMethod.POST, 819 "User/Search/GlobalName/0", 820 json={"displayNamePrefix": name}, 821 ) 822 assert isinstance(resp, dict) 823 return resp
Search for users by their global name and return all users who share this name.
Parameters
- name (
str): The user name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the found users.
Raises
aiobungie.NotFound: The user(s) was not found.
825 async def fetch_clan_from_id( 826 self, id: int, /, access_token: typing.Optional[str] = None 827 ) -> typedefs.JSONObject: 828 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 829 resp = await self._request( 830 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 831 ) 832 assert isinstance(resp, dict) 833 return resp
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
835 async def fetch_clan( 836 self, 837 name: str, 838 /, 839 access_token: typing.Optional[str] = None, 840 *, 841 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 842 ) -> typedefs.JSONObject: 843 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 844 resp = await self._request( 845 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 846 ) 847 assert isinstance(resp, dict) 848 return resp
Fetch a Clan by its name. This method will return the first clan found with given name name.
Parameters
- name (
str): The clan name.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group type, Default is one.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
850 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 851 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 852 resp = await self._request( 853 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 854 ) 855 assert isinstance(resp, dict) 856 return resp
Fetch the admins and founder members of the clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan admins and founder members.
Raises
aiobungie.NotFound: The clan was not found.
858 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 859 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 860 resp = await self._request( 861 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 862 ) 863 assert isinstance(resp, list) 864 return resp
Fetch a clan's conversations.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the conversations.
866 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 867 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 868 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 869 assert isinstance(resp, dict) 870 return resp
Fetch a Bungie Application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application.
872 async def fetch_character( 873 self, 874 member_id: int, 875 membership_type: typedefs.IntAnd[enums.MembershipType], 876 character_id: int, 877 components: list[enums.ComponentType], 878 auth: typing.Optional[str] = None, 879 ) -> typedefs.JSONObject: 880 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 881 collector = _collect_components(components) 882 response = await self._request( 883 RequestMethod.GET, 884 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 885 f"Character/{character_id}/?components={collector}", 886 auth=auth, 887 ) 888 assert isinstance(response, dict) 889 return response
Fetch a Destiny 2 player's characters.
Parameters
- member_id (
int): A valid bungie member id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type. - character_id (
int): The character id to return. - components (
list[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the requested character.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
891 async def fetch_activities( 892 self, 893 member_id: int, 894 character_id: int, 895 mode: typedefs.IntAnd[enums.GameMode], 896 membership_type: typedefs.IntAnd[ 897 enums.MembershipType 898 ] = enums.MembershipType.ALL, 899 *, 900 page: int = 0, 901 limit: int = 1, 902 ) -> typedefs.JSONObject: 903 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 904 resp = await self._request( 905 RequestMethod.GET, 906 f"Destiny2/{int(membership_type)}/Account/" 907 f"{member_id}/Character/{character_id}/Stats/Activities" 908 f"/?mode={int(mode)}&count={limit}&page={page}", 909 ) 910 assert isinstance(resp, dict) 911 return resp
Fetch a Destiny 2 activity for the specified user id and character.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Member ship type, if nothing was passed than it will return all. - page (
int): The page number. Default to1 - limit (
int): Limit the returned result. Default to1
Returns
aiobungie.typedefs.JSONObject: A JSON object of the player's activities.
Raises
aiobungie.NotFound: The activity was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
913 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 914 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 915 resp = await self._request( 916 RequestMethod.GET, 917 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 918 ) 919 assert isinstance(resp, dict) 920 return resp
922 async def fetch_profile( 923 self, 924 membership_id: int, 925 type: typedefs.IntAnd[enums.MembershipType], 926 components: list[enums.ComponentType], 927 auth: typing.Optional[str] = None, 928 ) -> typedefs.JSONObject: 929 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 930 collector = _collect_components(components) 931 response = await self._request( 932 RequestMethod.GET, 933 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 934 auth=auth, 935 ) 936 assert isinstance(response, dict) 937 return response
Fetch a bungie profile.
Parameters
- membership_id (
int): The member's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): A valid membership type. - components (
list[aiobungie.ComponentType]): A list of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found profile.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
939 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 940 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 941 response = await self._request( 942 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 943 ) 944 assert isinstance(response, dict) 945 return response
Fetch a Destiny definition item given its type and hash.
Parameters
- type (
str): Entity's type definition. - hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the definition data.
947 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 948 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 949 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 950 assert isinstance(resp, dict) 951 return resp
Fetch a Destiny inventory item entity given a its hash.
Parameters
- hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the inventory item.
953 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 954 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 955 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 956 assert isinstance(resp, dict) 957 return resp
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the objetive data.
959 async def fetch_groups_for_member( 960 self, 961 member_id: int, 962 member_type: typedefs.IntAnd[enums.MembershipType], 963 /, 964 *, 965 filter: int = 0, 966 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 967 ) -> typedefs.JSONObject: 968 resp = await self._request( 969 RequestMethod.GET, 970 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 971 ) 972 assert isinstance(resp, dict) 973 return resp
Fetch the information about the groups for a member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
975 async def fetch_potential_groups_for_member( 976 self, 977 member_id: int, 978 member_type: typedefs.IntAnd[enums.MembershipType], 979 /, 980 *, 981 filter: int = 0, 982 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 983 ) -> typedefs.JSONObject: 984 resp = await self._request( 985 RequestMethod.GET, 986 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 987 ) 988 assert isinstance(resp, dict) 989 return resp
Get information about the groups that a given member has applied to or been invited to.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
991 async def fetch_clan_members( 992 self, 993 clan_id: int, 994 /, 995 *, 996 name: typing.Optional[str] = None, 997 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 998 ) -> typedefs.JSONObject: 999 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1000 resp = await self._request( 1001 RequestMethod.GET, 1002 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 1003 ) 1004 assert isinstance(resp, dict) 1005 return resp
Fetch all Bungie Clan members.
Parameters
- clan_id (
builsins.int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): An optional clan member's membership type. Default is set toaiobungie.MembershipType.NONEWhich returns the first matched clan member by their name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of clan members.
Raises
aiobungie.NotFound: The clan was not found.
1007 async def fetch_hardlinked_credentials( 1008 self, 1009 credential: int, 1010 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1011 /, 1012 ) -> typedefs.JSONObject: 1013 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1014 resp = await self._request( 1015 RequestMethod.GET, 1016 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1017 ) 1018 assert isinstance(resp, dict) 1019 return resp
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.typedefs.IntAnd[aiobungie.CredentialType]): The crededntial type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user hard linked types.
1021 async def fetch_user_credentials( 1022 self, access_token: str, membership_id: int, / 1023 ) -> typedefs.JSONArray: 1024 resp = await self._request( 1025 RequestMethod.GET, 1026 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1027 auth=access_token, 1028 ) 1029 assert isinstance(resp, list) 1030 return resp
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the returned credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1032 async def insert_socket_plug( 1033 self, 1034 action_token: str, 1035 /, 1036 instance_id: int, 1037 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1038 character_id: int, 1039 membership_type: typedefs.IntAnd[enums.MembershipType], 1040 ) -> typedefs.JSONObject: 1041 1042 if isinstance(plug, builders.PlugSocketBuilder): 1043 plug = plug.collect() 1044 1045 body = { 1046 "actionToken": action_token, 1047 "itemInstanceId": instance_id, 1048 "plug": plug, 1049 "characterId": character_id, 1050 "membershipType": int(membership_type), 1051 } 1052 resp = await self._request( 1053 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1054 ) 1055 assert isinstance(resp, dict) 1056 return resp
Insert a plug into a socketed item.
OAuth2: AdvancedWriteActions scope is required
Parameters
- action_token (
str): Action token provided by the AwaGetActionToken API call. - instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1058 async def insert_socket_plug_free( 1059 self, 1060 access_token: str, 1061 /, 1062 instance_id: int, 1063 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1064 character_id: int, 1065 membership_type: typedefs.IntAnd[enums.MembershipType], 1066 ) -> typedefs.JSONObject: 1067 1068 if isinstance(plug, builders.PlugSocketBuilder): 1069 plug = plug.collect() 1070 1071 body = { 1072 "itemInstanceId": instance_id, 1073 "plug": plug, 1074 "characterId": character_id, 1075 "membershipType": int(membership_type), 1076 } 1077 resp = await self._request( 1078 RequestMethod.POST, 1079 "Destiny2/Actions/Items/InsertSocketPlugFree", 1080 json=body, 1081 auth=access_token, 1082 ) 1083 assert isinstance(resp, dict) 1084 return resp
Insert a plug into a socketed item. This doesn't require an Action token.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1086 async def set_item_lock_state( 1087 self, 1088 access_token: str, 1089 state: bool, 1090 /, 1091 item_id: int, 1092 character_id: int, 1093 membership_type: typedefs.IntAnd[enums.MembershipType], 1094 ) -> int: 1095 body = { 1096 "state": state, 1097 "itemId": item_id, 1098 "characterId": character_id, 1099 "membership_type": int(membership_type), 1100 } 1101 response = await self._request( 1102 RequestMethod.POST, 1103 "Destiny2/Actions/Items/SetLockState", 1104 json=body, 1105 auth=access_token, 1106 ) 1107 assert isinstance(response, int) 1108 return response
Set the Lock State for an instanced item.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1110 async def set_quest_track_state( 1111 self, 1112 access_token: str, 1113 state: bool, 1114 /, 1115 item_id: int, 1116 character_id: int, 1117 membership_type: typedefs.IntAnd[enums.MembershipType], 1118 ) -> int: 1119 body = { 1120 "state": state, 1121 "itemId": item_id, 1122 "characterId": character_id, 1123 "membership_type": int(membership_type), 1124 } 1125 response = await self._request( 1126 RequestMethod.POST, 1127 "Destiny2/Actions/Items/SetTrackedState", 1128 json=body, 1129 auth=access_token, 1130 ) 1131 assert isinstance(response, int) 1132 return response
Set the Tracking State for an instanced Quest or Bounty.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1134 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1135 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1136 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1137 assert isinstance(path, dict) 1138 return path
Fetch the manifest JSON paths.
Returns
typedefs.JSONObject: The manifest JSON paths.
1140 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1141 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1142 _ensure_manifest_language(language) 1143 1144 content = await self.fetch_manifest_path() 1145 resp = await self._request( 1146 RequestMethod.GET, 1147 content["mobileWorldContentPaths"][language], 1148 unwrapping="read", 1149 base=True, 1150 ) 1151 assert isinstance(resp, bytes) 1152 return resp
Read raw manifest SQLite database bytes response.
This method can be used to write the bytes to zipped file and then extract it to get the manifest content.
Parameters
- language (
str): The manifest database language bytes to get.
Returns
bytes: The bytes to read and write the manifest database.
1154 async def download_manifest( 1155 self, 1156 language: str = "en", 1157 name: str = "manifest", 1158 path: typing.Union[pathlib.Path, str] = ".", 1159 *, 1160 force: bool = False, 1161 ) -> None: 1162 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1163 complete_path = _get_path(name, path, sql=True) 1164 1165 if complete_path.exists() and force: 1166 if force: 1167 _LOG.info( 1168 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1169 ) 1170 complete_path.unlink(missing_ok=True) 1171 1172 return await self.download_manifest(language, name, path, force=force) 1173 1174 else: 1175 raise FileExistsError( 1176 "Manifest file already exists, " 1177 "To force download, set the `force` parameter to `True`." 1178 ) 1179 1180 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1181 data_bytes = await self.read_manifest_bytes(language) 1182 await asyncio.get_running_loop().run_in_executor( 1183 None, _write_sqlite_bytes, data_bytes, path, name 1184 )
A helper method to download the manifest.
Note
This method downloads the sqlite database and not JSON.
Use RESTInterface.download_json_manifest for the JSON version.
Parameters
- language (
str): The manifest language to download, Default is english. - path (
str|pathlib.Path): The path to save the manifest sqlite database. Example"D:/", Default is the current directory. - name (
str): The manifest database file name. Default ismanifest - force (
bool): Whether to force the download. Default isFalse. However if set to true the old file will get removed and a new one will being to download.
Returns
None
Raises
FileNotFoundError: If the manifest file exists andforceisFalse.ValueError: If the provided language was not recognized.
1186 async def download_json_manifest( 1187 self, 1188 file_name: str = "manifest", 1189 path: typing.Union[str, pathlib.Path] = ".", 1190 language: str = "en", 1191 ) -> None: 1192 _ensure_manifest_language(language) 1193 1194 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1195 1196 content = await self.fetch_manifest_path() 1197 json_bytes = await self._request( 1198 RequestMethod.GET, 1199 content["jsonWorldContentPaths"][language], 1200 unwrapping="read", 1201 base=True, 1202 ) 1203 1204 await asyncio.get_running_loop().run_in_executor( 1205 None, _write_json_bytes, json_bytes, file_name, path 1206 ) 1207 _LOG.info("Finished downloading manifest JSON.")
Download the Bungie manifest json file.
Parameters
- file_name (
str): The file name to save the manifest json file. Default ismanifest. - path (
str|pathlib.Path): The path to save the manifest json file. Default is the current directory. Example"D:/" - language (
str): The manifest database language bytes to get. Default is English.
1209 async def fetch_manifest_version(self) -> str: 1210 return typing.cast(str, (await self.fetch_manifest_path())["version"])
Fetch the manifest version.
Returns
str: The manifest version.
1212 async def fetch_linked_profiles( 1213 self, 1214 member_id: int, 1215 member_type: typedefs.IntAnd[enums.MembershipType], 1216 /, 1217 *, 1218 all: bool = False, 1219 ) -> typedefs.JSONObject: 1220 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1221 resp = await self._request( 1222 RequestMethod.GET, 1223 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1224 ) 1225 assert isinstance(resp, dict) 1226 return resp
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether thry're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.typedefs.JSONObject- A JSON object which contains an Array of profiles, an Array of profiles with errors and Bungie.Net membership
1236 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1237 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1238 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1239 assert isinstance(resp, dict) 1240 return resp
Fetch the available milestones.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information about the milestones.
1242 async def fetch_public_milestone_content( 1243 self, milestone_hash: int, / 1244 ) -> typedefs.JSONObject: 1245 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1246 resp = await self._request( 1247 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information related to the fetched milestone.
1252 async def fetch_current_user_memberships( 1253 self, access_token: str, / 1254 ) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request( 1257 RequestMethod.GET, 1258 "User/GetMembershipsForCurrentUser/", 1259 auth=access_token, 1260 ) 1261 assert isinstance(resp, dict) 1262 return resp
Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.
This requires OAuth2 scope enabled and the valid Bearer access_token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the bungie net user and destiny memberships of this account.
1264 async def equip_item( 1265 self, 1266 access_token: str, 1267 /, 1268 item_id: int, 1269 character_id: int, 1270 membership_type: typedefs.IntAnd[enums.MembershipType], 1271 ) -> None: 1272 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1273 payload = { 1274 "itemId": item_id, 1275 "characterId": character_id, 1276 "membershipType": int(membership_type), 1277 } 1278 1279 await self._request( 1280 RequestMethod.POST, 1281 "Destiny2/Actions/Items/EquipItem/", 1282 json=payload, 1283 auth=access_token, 1284 )
Equip an item to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item id. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1286 async def equip_items( 1287 self, 1288 access_token: str, 1289 /, 1290 item_ids: list[int], 1291 character_id: int, 1292 membership_type: typedefs.IntAnd[enums.MembershipType], 1293 ) -> None: 1294 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1295 payload = { 1296 "itemIds": item_ids, 1297 "characterId": character_id, 1298 "membershipType": int(membership_type), 1299 } 1300 await self._request( 1301 RequestMethod.POST, 1302 "Destiny2/Actions/Items/EquipItems/", 1303 json=payload, 1304 auth=access_token, 1305 )
Equip multiple items to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_ids (
list[int]): A list of item ids. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1307 async def ban_clan_member( 1308 self, 1309 access_token: str, 1310 /, 1311 group_id: int, 1312 membership_id: int, 1313 membership_type: typedefs.IntAnd[enums.MembershipType], 1314 *, 1315 length: int = 0, 1316 comment: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1317 ) -> None: 1318 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1319 payload = {"comment": str(comment), "length": length} 1320 await self._request( 1321 RequestMethod.POST, 1322 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1323 json=payload, 1324 auth=access_token, 1325 )
Bans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to ban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- length (
int): An optional ban length. - comment (
aiobungie.UndefinedOr[str]): An optional comment to this ban. Default isUNDEFINED
1327 async def unban_clan_member( 1328 self, 1329 access_token: str, 1330 /, 1331 group_id: int, 1332 membership_id: int, 1333 membership_type: typedefs.IntAnd[enums.MembershipType], 1334 ) -> None: 1335 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1336 await self._request( 1337 RequestMethod.POST, 1338 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1339 auth=access_token, 1340 )
Unbans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to unban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
1342 async def kick_clan_member( 1343 self, 1344 access_token: str, 1345 /, 1346 group_id: int, 1347 membership_id: int, 1348 membership_type: typedefs.IntAnd[enums.MembershipType], 1349 ) -> typedefs.JSONObject: 1350 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1351 resp = await self._request( 1352 RequestMethod.POST, 1353 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1354 auth=access_token, 1355 ) 1356 assert isinstance(resp, dict) 1357 return resp
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the group that the member has been kicked from.
1359 async def edit_clan( 1360 self, 1361 access_token: str, 1362 /, 1363 group_id: int, 1364 *, 1365 name: typedefs.NoneOr[str] = None, 1366 about: typedefs.NoneOr[str] = None, 1367 motto: typedefs.NoneOr[str] = None, 1368 theme: typedefs.NoneOr[str] = None, 1369 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1370 is_public: typedefs.NoneOr[bool] = None, 1371 locale: typedefs.NoneOr[str] = None, 1372 avatar_image_index: typedefs.NoneOr[int] = None, 1373 membership_option: typedefs.NoneOr[ 1374 typedefs.IntAnd[enums.MembershipOption] 1375 ] = None, 1376 allow_chat: typedefs.NoneOr[bool] = None, 1377 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1378 call_sign: typedefs.NoneOr[str] = None, 1379 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1380 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1381 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1382 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1383 ) -> None: 1384 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1385 payload = { 1386 "name": name, 1387 "about": about, 1388 "motto": motto, 1389 "theme": theme, 1390 "tags": tags, 1391 "isPublic": is_public, 1392 "avatarImageIndex": avatar_image_index, 1393 "isPublicTopicAdminOnly": is_public_topic_admin, 1394 "allowChat": allow_chat, 1395 "chatSecurity": chat_security, 1396 "callsign": call_sign, 1397 "homepage": homepage, 1398 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1399 "defaultPublicity": default_publicity, 1400 "locale": locale, 1401 } 1402 if membership_option is not None: 1403 payload["membershipOption"] = int(membership_option) 1404 1405 await self._request( 1406 RequestMethod.POST, 1407 f"GroupV2/{group_id}/Edit", 1408 json=payload, 1409 auth=access_token, 1410 )
Edit a clan.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id to edit.
Other Parameters
- name (
aiobungie.typedefs.NoneOr[str]): The name to edit the clan with. - about (
aiobungie.typedefs.NoneOr[str]): The about section to edit the clan with. - motto (
aiobungie.typedefs.NoneOr[str]): The motto section to edit the clan with. - theme (
aiobungie.typedefs.NoneOr[str]): The theme name to edit the clan with. - tags (
aiobungie.typedefs.NoneOr[collections.Sequence[str]]): A sequence of strings to replace the clan tags with. - is_public (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan will set to private. If provided and set toFalse, The clan will set to public whether it was or not. - locale (
aiobungie.typedefs.NoneOr[str]): The locale section to edit the clan with. - avatar_image_index (
aiobungie.typedefs.NoneOr[int]): The clan avatar image index to edit the clan with. - membership_option :
aiobungie.typedefs.NoneOr[aiobungie.typedefs.IntAnd[aiobungie.MembershipOption]]# noqa (E501 # Line too long): The clan membership option to edit it with. - allow_chat (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan members will be allowed to chat. If provided and set toFalse, The clan members will not be allowed to chat. - chat_security (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to0, The clan chat security will be edited toGrouponly. If provided and set to1, The clan chat security will be edited toAdminonly. - call_sign (
aiobungie.typedefs.NoneOr[str]): The clan call sign to edit it with. - homepage (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat homepage will be edited toWall. If provided and set to1, The clan chat homepage will be edited toForum. If provided and set to0, The clan chat homepage will be edited toAllianceForum. - enable_invite_messaging_for_admins (
aiobungie.typedefs.NoneOr[bool]): ??? - default_publicity (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat publicity will be edited toPublic. If provided and set to1, The clan chat publicity will be edited toAlliance. If provided and set to2, The clan chat publicity will be edited toPrivate. - is_public_topic_admin (
aiobungie.typedefs.NoneOr[bool]): ???
1412 async def edit_clan_options( 1413 self, 1414 access_token: str, 1415 /, 1416 group_id: int, 1417 *, 1418 invite_permissions_override: typedefs.NoneOr[bool] = None, 1419 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1420 host_guided_game_permission_override: typedefs.NoneOr[ 1421 typing.Literal[0, 1, 2] 1422 ] = None, 1423 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1424 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1425 ) -> None: 1426 1427 payload = { 1428 "InvitePermissionOverride": invite_permissions_override, 1429 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1430 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1431 "UpdateBannerPermissionOverride": update_banner_permission_override, 1432 "JoinLevel": int(join_level) if join_level else None, 1433 } 1434 1435 await self._request( 1436 RequestMethod.POST, 1437 f"GroupV2/{group_id}/EditFounderOptions", 1438 json=payload, 1439 auth=access_token, 1440 )
Edit the clan options.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id.
Other Parameters
- invite_permissions_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - update_culture_permissionOverride (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - host_guided_game_permission_override (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides:0-> None,1-> Beginner2-> Member. Default is Member for clans, None for groups, although this means nothing for groups. - update_banner_permission_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - join_level (
aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default isaiobungie.ClanMemberType.BEGINNER
1442 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1443 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1444 resp = await self._request( 1445 RequestMethod.GET, 1446 "Social/Friends/", 1447 auth=access_token, 1448 ) 1449 assert isinstance(resp, dict) 1450 return resp
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the bungie friends's data.
1452 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1453 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1454 resp = await self._request( 1455 RequestMethod.GET, 1456 "Social/Friends/Requests", 1457 auth=access_token, 1458 ) 1459 assert isinstance(resp, dict) 1460 return resp
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of incoming requests and outgoing requests.
1462 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1463 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1464 await self._request( 1465 RequestMethod.POST, 1466 f"Social/Friends/Requests/Accept/{member_id}", 1467 auth=access_token, 1468 )
Accepts a friend relationship with the target user. The user must be on your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to accept.
1470 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 await self._request( 1473 RequestMethod.POST, 1474 f"Social/Friends/Add/{member_id}", 1475 auth=access_token, 1476 )
Requests a friend relationship with the target user.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to send the request to.
1478 async def decline_friend_request( 1479 self, access_token: str, /, member_id: int 1480 ) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Decline/{member_id}", 1485 auth=access_token, 1486 )
Decline a friend request with the target user. The user must be in your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to decline.
1488 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Remove/{member_id}", 1493 auth=access_token, 1494 )
Removes a friend from your friend list. The user must be in your friend list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove.
1496 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1497 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1498 await self._request( 1499 RequestMethod.POST, 1500 f"Social/Friends/Requests/Remove/{member_id}", 1501 auth=access_token, 1502 )
Removes a friend from your friend list requests. The user must be in your outgoing request list.
.. note : This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove from the requested friend list.
1504 async def approve_all_pending_group_users( 1505 self, 1506 access_token: str, 1507 /, 1508 group_id: int, 1509 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1510 ) -> None: 1511 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1512 await self._request( 1513 RequestMethod.POST, 1514 f"GroupV2/{group_id}/Members/ApproveAll", 1515 auth=access_token, 1516 json={"message": str(message)}, 1517 )
Apporve all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1519 async def deny_all_pending_group_users( 1520 self, 1521 access_token: str, 1522 /, 1523 group_id: int, 1524 *, 1525 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1526 ) -> None: 1527 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1528 await self._request( 1529 RequestMethod.POST, 1530 f"GroupV2/{group_id}/Members/DenyAll", 1531 auth=access_token, 1532 json={"message": str(message)}, 1533 )
Deny all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1535 async def add_optional_conversation( 1536 self, 1537 access_token: str, 1538 /, 1539 group_id: int, 1540 *, 1541 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1542 security: typing.Literal[0, 1] = 0, 1543 ) -> None: 1544 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1545 payload = {"chatName": str(name), "chatSecurity": security} 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/OptionalConversations/Add", 1549 json=payload, 1550 auth=access_token, 1551 )
Add a new chat channel to a group.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other parameters
name: aiobungie.UndefinedOr[str]
The chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
1553 async def edit_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 conversation_id: int, 1559 *, 1560 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1561 security: typing.Literal[0, 1] = 0, 1562 enable_chat: bool = False, 1563 ) -> None: 1564 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1565 payload = { 1566 "chatEnabled": enable_chat, 1567 "chatName": str(name), 1568 "chatSecurity": security, 1569 } 1570 await self._request( 1571 RequestMethod.POST, 1572 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1573 json=payload, 1574 auth=access_token, 1575 )
Edit the settings of this chat channel.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id. - conversation_id (
int): The conversation/chat id.
Other parameters
name: aiobungie.UndefinedOr[str]
The new chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The new security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
enable_chat : bool
Whether to enable chatting or not.
If set to True then chatting will be enabled. Otherwise it will be disabled.
1577 async def transfer_item( 1578 self, 1579 access_token: str, 1580 /, 1581 item_id: int, 1582 item_hash: int, 1583 character_id: int, 1584 member_type: typedefs.IntAnd[enums.MembershipType], 1585 *, 1586 stack_size: int = 1, 1587 vault: bool = False, 1588 ) -> None: 1589 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1590 payload = { 1591 "characterId": character_id, 1592 "membershipType": int(member_type), 1593 "itemId": item_id, 1594 "itemReferenceHash": item_hash, 1595 "stackSize": stack_size, 1596 "transferToVault": vault, 1597 } 1598 await self._request( 1599 RequestMethod.POST, 1600 "Destiny2/Actions/Items/TransferItem", 1601 json=payload, 1602 auth=access_token, 1603 )
Transfer an item from / to your vault.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id you to transfer. - item_hash (
int): The item hash. - character_id (
int): The character id to transfer the item from/to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to trasnfer this item to your valut or not. Defaults toFalse.
1605 async def pull_item( 1606 self, 1607 access_token: str, 1608 /, 1609 item_id: int, 1610 item_hash: int, 1611 character_id: int, 1612 member_type: typedefs.IntAnd[enums.MembershipType], 1613 *, 1614 stack_size: int = 1, 1615 vault: bool = False, 1616 ) -> None: 1617 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1618 payload = { 1619 "characterId": character_id, 1620 "membershipType": int(member_type), 1621 "itemId": item_id, 1622 "itemReferenceHash": item_hash, 1623 "stackSize": stack_size, 1624 "transferToVault": vault, 1625 } 1626 await self._request( 1627 RequestMethod.POST, 1628 "Destiny2/Actions/Items/PullFromPostmaster", 1629 json=payload, 1630 auth=access_token, 1631 )
pull an item from the postmaster.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id to pull. - item_hash (
int): The item hash. - character_id (
int): The character id to pull the item to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to pill this item to your valut or not. Defaults toFalse.
1633 async def fetch_fireteams( 1634 self, 1635 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1636 *, 1637 platform: typedefs.IntAnd[ 1638 fireteams.FireteamPlatform 1639 ] = fireteams.FireteamPlatform.ANY, 1640 language: typing.Union[ 1641 fireteams.FireteamLanguage, str 1642 ] = fireteams.FireteamLanguage.ALL, 1643 date_range: typedefs.IntAnd[ 1644 fireteams.FireteamDate 1645 ] = fireteams.FireteamDate.ALL, 1646 page: int = 0, 1647 slots_filter: int = 0, 1648 ) -> typedefs.JSONObject: 1649 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1650 resp = await self._request( 1651 RequestMethod.GET, 1652 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1653 ) 1654 assert isinstance(resp, dict) 1655 return resp
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1657 async def fetch_avaliable_clan_fireteams( 1658 self, 1659 access_token: str, 1660 group_id: int, 1661 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1662 *, 1663 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1664 language: typing.Union[fireteams.FireteamLanguage, str], 1665 date_range: typedefs.IntAnd[ 1666 fireteams.FireteamDate 1667 ] = fireteams.FireteamDate.ALL, 1668 page: int = 0, 1669 public_only: bool = False, 1670 slots_filter: int = 0, 1671 ) -> typedefs.JSONObject: 1672 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1673 resp = await self._request( 1674 RequestMethod.GET, 1675 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1676 json={"langFilter": str(language)}, 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1682 async def fetch_clan_fireteam( 1683 self, access_token: str, fireteam_id: int, group_id: int 1684 ) -> typedefs.JSONObject: 1685 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1686 resp = await self._request( 1687 RequestMethod.GET, 1688 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1689 auth=access_token, 1690 ) 1691 assert isinstance(resp, dict) 1692 return resp
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1694 async def fetch_my_clan_fireteams( 1695 self, 1696 access_token: str, 1697 group_id: int, 1698 *, 1699 include_closed: bool = True, 1700 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1701 language: typing.Union[fireteams.FireteamLanguage, str], 1702 filtered: bool = True, 1703 page: int = 0, 1704 ) -> typedefs.JSONObject: 1705 payload = {"groupFilter": filtered, "langFilter": str(language)} 1706 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1707 resp = await self._request( 1708 RequestMethod.GET, 1709 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1710 json=payload, 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, dict) 1714 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set toTrue, It will also return closed fireteams. If provided and set toFalse, It will only return public fireteams. Default isTrue. - platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set toTrue, it will filter by clan. Otherwise not. Default isTrue. - page (
int): The page number. By default its0which returns all available activities.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1716 async def fetch_private_clan_fireteams( 1717 self, access_token: str, group_id: int, / 1718 ) -> int: 1719 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1720 resp = await self._request( 1721 RequestMethod.GET, 1722 f"Fireteam/Clan/{group_id}/ActiveCount", 1723 auth=access_token, 1724 ) 1725 assert isinstance(resp, int) 1726 return resp
Fetch the active count of the clan fireteams that are only private.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id.
Returns
int: The active fireteams count. Max value returned is 25.
1728 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1729 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1730 resp = await self._request( 1731 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the post activity.
1736 async def search_entities( 1737 self, name: str, entity_type: str, *, page: int = 0 1738 ) -> typedefs.JSONObject: 1739 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1740 resp = await self._request( 1741 RequestMethod.GET, 1742 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1743 json={"page": page}, 1744 ) 1745 assert isinstance(resp, dict) 1746 return resp
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinition
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the searched term.
1748 async def fetch_unique_weapon_history( 1749 self, 1750 membership_id: int, 1751 character_id: int, 1752 membership_type: typedefs.IntAnd[enums.MembershipType], 1753 ) -> typedefs.JSONObject: 1754 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1758 ) 1759 assert isinstance(resp, dict) 1760 return resp
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the returned weapons.
1762 async def fetch_item( 1763 self, 1764 member_id: int, 1765 item_id: int, 1766 membership_type: typedefs.IntAnd[enums.MembershipType], 1767 components: list[enums.ComponentType], 1768 ) -> typedefs.JSONObject: 1769 collector = _collect_components(components) 1770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1771 resp = await self._request( 1772 RequestMethod.GET, 1773 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1774 ) 1775 assert isinstance(resp, dict) 1776 return resp
Fetch an instanced Destiny 2 item's details.
Parameters
- member_id (
int): The membership id of the Destiny 2 player. - item_id (
int): The instance id of the item. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type of the Destiny 2 player. - components (
list[aiobungie.ComponentType]): A list of components to retrieve.
Returns
aiobungie.typedefs.JSONObject: A JSON object response contains the fetched item with its components.
1778 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1779 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1780 resp = await self._request( 1781 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1782 ) 1783 assert isinstance(resp, dict) 1784 return resp
Fetch the weekly reward state for a clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON response of the clan rewards state.
1786 async def fetch_available_locales(self) -> typedefs.JSONObject: 1787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1788 resp = await self._request( 1789 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1790 ) 1791 assert isinstance(resp, dict) 1792 return resp
Fetch available locales at Bungie.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains a list of all available localization cultures.
1794 async def fetch_common_settings(self) -> typedefs.JSONObject: 1795 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1796 resp = await self._request(RequestMethod.GET, "Settings") 1797 assert isinstance(resp, dict) 1798 return resp
Fetch the common settings used by Bungie's envirotment.
Returns
aiobungie.typedefs.JSONObject: The common settings JSON object.
1800 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1802 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1803 assert isinstance(resp, dict) 1804 return resp
Fetch a user's specific system overrides.
Returns
aiobungie.typedefs.JSONObject: The system overrides JSON object.
1806 async def fetch_global_alerts( 1807 self, *, include_streaming: bool = False 1808 ) -> typedefs.JSONArray: 1809 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1810 resp = await self._request( 1811 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1812 ) 1813 assert isinstance(resp, list) 1814 return resp
Fetch any active global alerts.
Parameters
- include_streaming (
bool): If True, the returned results will include streaming alerts. Default is False.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the global alerts objects.
1816 async def awainitialize_request( 1817 self, 1818 access_token: str, 1819 type: typing.Literal[0, 1], 1820 membership_type: typedefs.IntAnd[enums.MembershipType], 1821 /, 1822 *, 1823 affected_item_id: typing.Optional[int] = None, 1824 character_id: typing.Optional[int] = None, 1825 ) -> typedefs.JSONObject: 1826 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1827 1828 body = {"type": type, "membershipType": int(membership_type)} 1829 1830 if affected_item_id is not None: 1831 body["affectedItemId"] = affected_item_id 1832 1833 if character_id is not None: 1834 body["characterId"] = character_id 1835 1836 resp = await self._request( 1837 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp
Initialize a request to perform an advanced write action.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - type (
typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means itNone. Otherwise if 1 that means its insert plugs. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
- affected_item_id (
typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values. - character_id (
typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1842 async def awaget_action_token( 1843 self, access_token: str, correlation_id: str, / 1844 ) -> typedefs.JSONObject: 1845 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1846 resp = await self._request( 1847 RequestMethod.POST, 1848 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1849 auth=access_token, 1850 ) 1851 assert isinstance(resp, dict) 1852 return resp
Returns the action token if user approves the request.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - correlation_id (
str): The identifier for the advanced write action request.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1874 async def fetch_vendors( 1875 self, 1876 access_token: str, 1877 character_id: int, 1878 membership_id: int, 1879 membership_type: typedefs.IntAnd[enums.MembershipType], 1880 /, 1881 components: list[enums.ComponentType], 1882 filter: typing.Optional[int] = None, 1883 ) -> typedefs.JSONObject: 1884 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1885 components_ = _collect_components(components) 1886 route = ( 1887 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1888 f"/Character/{character_id}/Vendors/?components={components_}" 1889 ) 1890 1891 if filter is not None: 1892 route = route + f"&filter={filter}" 1893 1894 resp = await self._request( 1895 RequestMethod.GET, 1896 route, 1897 auth=access_token, 1898 ) 1899 assert isinstance(resp, dict) 1900 return resp
Get currently available vendors from the list of vendors that can possibly have rotating inventory.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
- filter (
int): Filters the type of items returned from the vendor. This can be left toNone.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1902 async def fetch_vendor( 1903 self, 1904 access_token: str, 1905 character_id: int, 1906 membership_id: int, 1907 membership_type: typedefs.IntAnd[enums.MembershipType], 1908 vendor_hash: int, 1909 /, 1910 components: list[enums.ComponentType], 1911 ) -> typedefs.JSONObject: 1912 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1913 components_ = _collect_components(components) 1914 resp = await self._request( 1915 RequestMethod.GET, 1916 ( 1917 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1918 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1919 ), 1920 auth=access_token, 1921 ) 1922 assert isinstance(resp, dict) 1923 return resp
Fetch details for a specific vendor.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - vendor_hash (
int): The vendor hash to return the details for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1925 async def fetch_application_api_usage( 1926 self, 1927 access_token: str, 1928 application_id: int, 1929 /, 1930 *, 1931 start: typing.Optional[datetime.datetime] = None, 1932 end: typing.Optional[datetime.datetime] = None, 1933 ) -> typedefs.JSONObject: 1934 1935 end_date, start_date = time.parse_date_range(end, start) 1936 resp = await self._request( 1937 RequestMethod.GET, 1938 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1939 auth=access_token, 1940 ) 1941 assert isinstance(resp, dict) 1942 return resp
Fetch a Bungie application's API usage.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - application_id (
int): The application id to get.
Other Parameters
start (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.If this is left to
None. It will return the last 24 hours.end (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.If this is left to
None. It will returnnow.
Example
import datetime
# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application usage details.
1944 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1945 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1946 assert isinstance(resp, list) 1947 return resp
Fetch details for applications created by Bungie.
Returns
aiobungie.typedefs.JSONArray: An array of Bungie created applications.
1954 async def fetch_content_by_id( 1955 self, id: int, locale: str, /, *, head: bool = False 1956 ) -> typedefs.JSONObject: 1957 resp = await self._request( 1958 RequestMethod.GET, 1959 f"Content/GetContentById/{id}/{locale}/", 1960 json={"head": head}, 1961 ) 1962 assert isinstance(resp, dict) 1963 return resp
1965 async def fetch_content_by_tag_and_type( 1966 self, locale: str, tag: str, type: str, *, head: bool = False 1967 ) -> typedefs.JSONObject: 1968 resp = await self._request( 1969 RequestMethod.GET, 1970 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1971 json={"head": head}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp
1976 async def search_content_with_text( 1977 self, 1978 locale: str, 1979 /, 1980 content_type: str, 1981 search_text: str, 1982 tag: str, 1983 *, 1984 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1985 source: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1986 ) -> typedefs.JSONObject: 1987 1988 body: typedefs.JSONObject = {} 1989 1990 body["ctype"] = content_type 1991 body["searchtext"] = search_text 1992 body["tag"] = tag 1993 1994 if page is not undefined.UNDEFINED: 1995 body["currentpage"] = page 1996 else: 1997 body["currentpage"] = 1 1998 1999 if source is not undefined.UNDEFINED: 2000 body["source"] = source 2001 else: 2002 source = "" 2003 resp = await self._request( 2004 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2005 ) 2006 assert isinstance(resp, dict) 2007 return resp
2009 async def search_content_by_tag_and_type( 2010 self, 2011 locale: str, 2012 tag: str, 2013 type: str, 2014 *, 2015 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 2016 ) -> typedefs.JSONObject: 2017 body: typedefs.JSONObject = {} 2018 body["currentpage"] = 1 if page is undefined.UNDEFINED else page 2019 resp = await self._request( 2020 RequestMethod.GET, 2021 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2022 json=body, 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp
2036 async def fetch_topics_page( 2037 self, 2038 category_filter: int, 2039 group: int, 2040 date_filter: int, 2041 sort: typing.Union[str, bytes], 2042 *, 2043 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 2044 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 2045 tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED, 2046 ) -> typedefs.JSONObject: 2047 2048 body: typedefs.JSONObject = {} 2049 if locales is not undefined.UNDEFINED: 2050 body["locales"] = ",".join(str(locales)) 2051 else: 2052 body["locales"] = ",".join([]) 2053 2054 if tag_filter is not undefined.UNDEFINED: 2055 body["tagstring"] = tag_filter 2056 else: 2057 body["tagstring"] = "" 2058 2059 page = 0 if page is not undefined.UNDEFINED else page 2060 2061 resp = await self._request( 2062 RequestMethod.GET, 2063 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2064 json=body, 2065 ) 2066 assert isinstance(resp, dict) 2067 return resp
2069 async def fetch_core_topics_page( 2070 self, 2071 category_filter: int, 2072 date_filter: int, 2073 sort: typing.Union[str, bytes], 2074 *, 2075 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 2076 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 2077 ) -> typedefs.JSONObject: 2078 body: typedefs.JSONObject = {} 2079 2080 if locales is not undefined.UNDEFINED: 2081 body["locales"] = ",".join(str(locales)) 2082 else: 2083 body["locales"] = ",".join([]) 2084 2085 resp = await self._request( 2086 RequestMethod.GET, 2087 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}" 2088 f"/{sort!s}/{date_filter}/{category_filter}/", 2089 json=body, 2090 ) 2091 assert isinstance(resp, dict) 2092 return resp
2094 async def fetch_posts_threaded_page( 2095 self, 2096 parent_post: bool, 2097 page: int, 2098 page_size: int, 2099 parent_post_id: int, 2100 reply_size: int, 2101 root_thread_mode: bool, 2102 sort_mode: int, 2103 show_banned: typing.Optional[str] = None, 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2108 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2109 json={"showbanned": show_banned}, 2110 ) 2111 assert isinstance(resp, dict) 2112 return resp
2114 async def fetch_posts_threaded_page_from_child( 2115 self, 2116 child_id: bool, 2117 page: int, 2118 page_size: int, 2119 reply_size: int, 2120 root_thread_mode: bool, 2121 sort_mode: int, 2122 show_banned: typing.Optional[str] = None, 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2127 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2128 json={"showbanned": show_banned}, 2129 ) 2130 assert isinstance(resp, dict) 2131 return resp
2133 async def fetch_post_and_parent( 2134 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2135 ) -> typedefs.JSONObject: 2136 resp = await self._request( 2137 RequestMethod.GET, 2138 f"Forum/GetPostAndParent/{child_id}/", 2139 json={"showbanned": show_banned}, 2140 ) 2141 assert isinstance(resp, dict) 2142 return resp
2144 async def fetch_posts_and_parent_awaiting( 2145 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2146 ) -> typedefs.JSONObject: 2147 resp = await self._request( 2148 RequestMethod.GET, 2149 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2150 json={"showbanned": show_banned}, 2151 ) 2152 assert isinstance(resp, dict) 2153 return resp
2183 async def fetch_recommended_groups( 2184 self, 2185 accecss_token: str, 2186 /, 2187 *, 2188 date_range: int = 0, 2189 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2190 ) -> typedefs.JSONArray: 2191 resp = await self._request( 2192 RequestMethod.POST, 2193 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2194 auth=accecss_token, 2195 ) 2196 assert isinstance(resp, list) 2197 return resp
2204 async def fetch_user_clan_invite_setting( 2205 self, 2206 access_token: str, 2207 /, 2208 membership_type: typedefs.IntAnd[enums.MembershipType], 2209 ) -> bool: 2210 resp = await self._request( 2211 RequestMethod.GET, 2212 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2213 auth=access_token, 2214 ) 2215 assert isinstance(resp, bool) 2216 return resp
2218 async def fetch_banned_group_members( 2219 self, access_token: str, group_id: int, /, *, page: int = 1 2220 ) -> typedefs.JSONObject: 2221 resp = await self._request( 2222 RequestMethod.GET, 2223 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2224 auth=access_token, 2225 ) 2226 assert isinstance(resp, dict) 2227 return resp
2229 async def fetch_pending_group_memberships( 2230 self, access_token: str, group_id: int, /, *, current_page: int = 1 2231 ) -> typedefs.JSONObject: 2232 resp = await self._request( 2233 RequestMethod.GET, 2234 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2235 auth=access_token, 2236 ) 2237 assert isinstance(resp, dict) 2238 return resp
2240 async def fetch_invited_group_memberships( 2241 self, access_token: str, group_id: int, /, *, current_page: int = 1 2242 ) -> typedefs.JSONObject: 2243 resp = await self._request( 2244 RequestMethod.GET, 2245 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2246 auth=access_token, 2247 ) 2248 assert isinstance(resp, dict) 2249 return resp
2251 async def invite_member_to_group( 2252 self, 2253 access_token: str, 2254 /, 2255 group_id: int, 2256 membership_id: int, 2257 membership_type: typedefs.IntAnd[enums.MembershipType], 2258 *, 2259 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.POST, 2263 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2264 auth=access_token, 2265 json={"message": str(message)}, 2266 ) 2267 assert isinstance(resp, dict) 2268 return resp
2270 async def cancel_group_member_invite( 2271 self, 2272 access_token: str, 2273 /, 2274 group_id: int, 2275 membership_id: int, 2276 membership_type: typedefs.IntAnd[enums.MembershipType], 2277 ) -> typedefs.JSONObject: 2278 resp = await self._request( 2279 RequestMethod.POST, 2280 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2281 auth=access_token, 2282 ) 2283 assert isinstance(resp, dict) 2284 return resp
2291 async def fetch_historical_stats( 2292 self, 2293 character_id: int, 2294 membership_id: int, 2295 membership_type: typedefs.IntAnd[enums.MembershipType], 2296 day_start: datetime.datetime, 2297 day_end: datetime.datetime, 2298 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2299 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2300 *, 2301 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2302 ) -> typedefs.JSONObject: 2303 2304 end, start = time.parse_date_range(day_end, day_start) 2305 resp = await self._request( 2306 RequestMethod.GET, 2307 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2308 json={ 2309 "dayend": end, 2310 "daystart": start, 2311 "groups": [str(int(group)) for group in groups], 2312 "modes": [str(int(mode)) for mode in modes], 2313 "periodType": int(period_type), 2314 }, 2315 ) 2316 assert isinstance(resp, dict) 2317 return resp
Fetch historical stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - day_start (
datetime.datetime): The start of the day to return the stats for. - day_end (
datetime.datetime): The end of the day to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return. - modes (
list[aiobungie.GameMode | int]): A list of game modes to return. - period_type (
aiobungie.enums.PeriodType): The period type to return the stats for. This will returnALL_TIMEby default if not modified.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats.
2319 async def fetch_historical_stats_for_account( 2320 self, 2321 membership_id: int, 2322 membership_type: typedefs.IntAnd[enums.MembershipType], 2323 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2324 ) -> typedefs.JSONObject: 2325 resp = await self._request( 2326 RequestMethod.GET, 2327 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2328 json={"groups": [str(int(group)) for group in groups]}, 2329 ) 2330 assert isinstance(resp, dict) 2331 return resp
Fetch historical stats for an account's membership.
Parameters
- membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats for the account. This includes both the character and account stats.
2333 async def fetch_aggregated_activity_stats( 2334 self, 2335 character_id: int, 2336 membership_id: int, 2337 membership_type: typedefs.IntAnd[enums.MembershipType], 2338 /, 2339 ) -> typedefs.JSONObject: 2340 resp = await self._request( 2341 RequestMethod.GET, 2342 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2343 f"Character/{character_id}/Stats/AggregateActivityStats/", 2344 ) 2345 assert isinstance(resp, dict) 2346 return resp
Fetch aggregated activity stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the aggregated activity stats.
236class RESTPool: 237 """Pool of `RESTClient` instances. 238 239 This allows to create multiple instances of `RESTClient`s that can be acquired 240 which share the same config and metadata. 241 242 Example 243 ------- 244 ```py 245 import aiobungie 246 import asyncio 247 248 client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret') 249 250 # Using a context manager to acquire an instance 251 # of the pool and close the connection after finishing. 252 253 async def first() -> str: 254 async with client_pool.acquire() as client: 255 return client.build_oauth2_url() 256 257 async def second() -> None: 258 async with client_pool.acquire() as client: 259 new_tokens = await client.refresh_access_token("token") 260 client.metadata['tokens'] = new_tokens 261 262 # Client instances are independent from first and second. 263 await asyncio.gather(first(), second()) 264 ``` 265 266 Parameters 267 ---------- 268 token : `str` 269 A valid application token from Bungie's developer portal. 270 271 Other Parameters 272 ---------------- 273 max_retries : `int` 274 The max retries number to retry if the request hit a `5xx` status code. 275 max_ratelimit_retries : `int` 276 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 277 client_secret : `typing.Optional[str]` 278 An optional application client secret, 279 This is only needed if you're fetching OAuth2 tokens with this client. 280 client_id : `typing.Optional[int]` 281 An optional application client id, 282 This is only needed if you're fetching OAuth2 tokens with this client. 283 enable_debugging : `bool | str` 284 Whether to enable logging responses or not. 285 286 Logging Levels 287 -------------- 288 * `False`: This will disable logging. 289 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 290 Like the response status, route, taken time and so on. 291 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 292 """ 293 294 __slots__ = ( 295 "_token", 296 "_max_retries", 297 "_client_secret", 298 "_client_id", 299 "_max_rate_limit_retries", 300 "_metadata", 301 "_enable_debug", 302 ) 303 304 # Looks like mypy doesn't like this. 305 if typing.TYPE_CHECKING: 306 _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int] 307 308 def __init__( 309 self, 310 token: str, 311 /, 312 client_secret: typing.Optional[str] = None, 313 client_id: typing.Optional[int] = None, 314 *, 315 max_retries: int = 4, 316 max_rate_limit_retries: int = 3, 317 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 318 ) -> None: 319 self._client_secret = client_secret 320 self._client_id = client_id 321 self._token: str = token 322 self._max_retries = max_retries 323 self._max_rate_limit_retries = max_rate_limit_retries 324 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 325 self._enable_debug = enable_debugging 326 327 @property 328 def client_id(self) -> typing.Optional[int]: 329 return self._client_id 330 331 @property 332 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 333 """Pool's Metadata. This is different from client instance metadata.""" 334 return self._metadata 335 336 @typing.final 337 def acquire(self) -> RESTClient: 338 """Acquires a new `RESTClient` instance from this REST pool. 339 340 Returns 341 ------- 342 `RESTClient` 343 An instance of a REST client. 344 """ 345 instance = RESTClient( 346 self._token, 347 client_secret=self._client_secret, 348 client_id=self._client_id, 349 max_retries=self._max_retries, 350 max_ratelimit_retries=self._max_rate_limit_retries, 351 enable_debugging=self._enable_debug, 352 ) 353 return instance
Pool of RESTClient instances.
This allows to create multiple instances of RESTClients that can be acquired
which share the same config and metadata.
Example
import aiobungie
import asyncio
client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.
async def first() -> str:
async with client_pool.acquire() as client:
return client.build_oauth2_url()
async def second() -> None:
async with client_pool.acquire() as client:
new_tokens = await client.refresh_access_token("token")
client.metadata['tokens'] = new_tokens
# Client instances are independent from first and second.
await asyncio.gather(first(), second())
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information. Like the response status, route, taken time and so on."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
308 def __init__( 309 self, 310 token: str, 311 /, 312 client_secret: typing.Optional[str] = None, 313 client_id: typing.Optional[int] = None, 314 *, 315 max_retries: int = 4, 316 max_rate_limit_retries: int = 3, 317 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 318 ) -> None: 319 self._client_secret = client_secret 320 self._client_id = client_id 321 self._token: str = token 322 self._max_retries = max_retries 323 self._max_rate_limit_retries = max_rate_limit_retries 324 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 325 self._enable_debug = enable_debugging
Pool's Metadata. This is different from client instance metadata.
336 @typing.final 337 def acquire(self) -> RESTClient: 338 """Acquires a new `RESTClient` instance from this REST pool. 339 340 Returns 341 ------- 342 `RESTClient` 343 An instance of a REST client. 344 """ 345 instance = RESTClient( 346 self._token, 347 client_secret=self._client_secret, 348 client_id=self._client_id, 349 max_retries=self._max_retries, 350 max_ratelimit_retries=self._max_rate_limit_retries, 351 enable_debugging=self._enable_debug, 352 ) 353 return instance
Acquires a new RESTClient instance from this REST pool.
Returns
RESTClient: An instance of a REST client.
493@typing.final 494class Race(int, Enum): 495 """An Enum for Destiny races.""" 496 497 HUMAN = 0 498 AWOKEN = 1 499 EXO = 2 500 UNKNOWN = 3
An Enum for Destiny races.
143@typing.final 144class Raid(int, Enum): 145 """An Enum for all available raids in Destiny 2.""" 146 147 DSC = 910380154 148 """Deep Stone Crypt""" 149 150 LW = 2122313384 151 """Last Wish""" 152 153 VOG = 3881495763 154 """Normal Valut of Glass""" 155 156 GOS = 3458480158 157 """Garden Of Salvation"""
An Enum for all available raids in Destiny 2.
253@attrs.define(auto_exc=True) 254class RateLimitedError(HTTPError): 255 """Raised when too many request status code is returned.""" 256 257 http_status: http.HTTPStatus = attrs.field( 258 default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False 259 ) 260 """The request response http status.""" 261 262 url: typedefs.StrOrURL 263 """The URL/endpoint caused this error.""" 264 265 body: typing.Any 266 """The response body.""" 267 268 retry_after: float = attrs.field(default=0.0) 269 """The amount of seconds you need to wait before retrying to requests.""" 270 271 message: str = attrs.field(init=False) 272 """A Bungie human readable message describes the cause of the error.""" 273 274 @message.default # type: ignore 275 def _(self) -> str: 276 return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!" 277 278 def __str__(self) -> str: 279 return self.message
Raised when too many request status code is returned.
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default): 3 self.http_status = attr_dict['http_status'].default 4 self.url = url 5 self.body = body 6 self.retry_after = retry_after 7 self.message = __attr_factory_message(self) 8 BaseException.__init__(self, self.url,self.body,self.retry_after)
Method generated by attrs for class RateLimitedError.
Inherited Members
- builtins.BaseException
- with_traceback
48@typing.final 49class RecordState(enums.Flag): 50 """An enum for records component states.""" 51 52 NONE = 0 53 REDEEMED = 1 << 0 54 UNAVAILABLE = 1 << 1 55 OBJECTIVE_NOT_COMPLETED = 1 << 2 56 OBSCURED = 1 << 3 57 INVISIBLE = 1 << 4 58 ENTITLEMENT_UNOWNED = 1 << 5 59 CAN_EQUIP_TITLE = 1 << 6
An enum for records component states.
688@typing.final 689class Relationship(int, Enum): 690 """An enum for bungie friends relationship types.""" 691 692 UNKNOWN = 0 693 FRIEND = 1 694 INCOMING_REQUEST = 2 695 OUTGOING_REQUEST = 3
An enum for bungie friends relationship types.
217class RequestMethod(str, enums.Enum): 218 """HTTP request methods enum.""" 219 220 GET = "GET" 221 """GET methods.""" 222 POST = "POST" 223 """POST methods.""" 224 PUT = "PUT" 225 """PUT methods.""" 226 PATCH = "PATCH" 227 """PATCH methods.""" 228 DELETE = "DELETE" 229 """DELETE methods"""
HTTP request methods enum.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
248@attrs.define(auto_exc=True) 249class ResponseError(HTTPException): 250 """Exception for other HTTP response errors."""
Exception for other HTTP response errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class ResponseError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
515@typing.final 516class Stat(int, Enum): 517 """An Enum for Destiny 2 character stats.""" 518 519 NONE = 0 520 MOBILITY = 2996146975 521 RESILIENCE = 392767087 522 RECOVERY = 1943323491 523 DISCIPLINE = 1735777505 524 INTELLECT = 144602215 525 STRENGTH = 4244567218 526 LIGHT_POWER = 1935470627
An Enum for Destiny 2 character stats.
630@typing.final 631class TierType(int, Enum): 632 """An enum for a Destiny 2 item tier type.""" 633 634 UNKNOWN = 0 635 CURRENCY = 1 636 BASIC = 2 637 COMMON = 3 638 RARE = 4 639 SUPERIOR = 5 640 EXOTIC = 6
An enum for a Destiny 2 item tier type.
740@typing.final 741class TransferStatus(Flag): 742 """An enum for items transfer statuses.""" 743 744 CAN_TRANSFER = 0 745 """The item can be transferred.""" 746 IS_EQUIPPED = 1 << 0 747 """You can't transfer since the item is equipped.""" 748 NOT_TRASNFERRABLE = 1 << 1 749 """This item can not be transferred.""" 750 COULD_BE_TRANSFERRED = 1 << 2 751 """You can trasnfer the item. But the place you're trying to put it at has no space for it."""
An enum for items transfer statuses.
You can trasnfer the item. But the place you're trying to put it at has no space for it.
33class UndefinedType: 34 """An `UNDEFINED` type.""" 35 36 __instance: typing.Optional[UndefinedType] = None 37 38 def __bool__(self) -> typing.Literal[False]: 39 return False 40 41 def __int__(self) -> typing.Literal[0]: 42 return 0 43 44 def __repr__(self) -> str: 45 return "UNDEFINED" 46 47 def __str__(self) -> str: 48 return "UNDEFINED" 49 50 def __new__(cls) -> UndefinedType: 51 if cls.__instance is None: 52 o = super().__new__(cls) 53 cls.__instance = o 54 return cls.__instance
An UNDEFINED type.
75@typing.final 76class ValueUIStyle(int, enums.Enum): 77 AUTOMATIC = 0 78 FRACTION = 1 79 CHECK_BOX = 2 80 PERCENTAGE = 3 81 DATETIME = 4 82 FRACTION_FLOAT = 5 83 INTEGER = 6 84 TIME_DURATION = 7 85 HIDDEN = 8 86 MULTIPLIER = 9 87 GREEN_PIPS = 10 88 RED_PIPS = 11 89 EXPLICIT_PERCENTAGE = 12 90 RAW_FLOAT = 13 91 LEVEL_AND_REWARD = 14
An enumeration.
240@typing.final 241class Vendor(int, Enum): 242 """An Enum for all available vendors in Destiny 2.""" 243 244 ZAVALA = 69482069 245 XUR = 2190858386 246 BANSHE = 672118013 247 SPIDER = 863940356 248 SHAXX = 3603221665 249 KADI = 529635856 250 """Postmaster exo.""" 251 YUNA = 1796504621 252 """Asia servers only.""" 253 EVERVERSE = 3361454721 254 AMANDA = 460529231 255 """Amanda holiday""" 256 CROW = 3611983588 257 HAWTHORNE = 3347378076 258 ADA1 = 350061650 259 DRIFTER = 248695599 260 IKORA = 1976548992 261 SAINT = 765357505 262 """Saint-14""" 263 ERIS_MORN = 1616085565 264 SHAW_HAWN = 1816541247 265 """COSMODROME Guy""" 266 VARIKS = 2531198101
An Enum for all available vendors in Destiny 2.
529@typing.final 530class WeaponType(int, Enum): 531 """Enums for The three Destiny Weapon Types""" 532 533 NONE = 0 534 KINETIC = 1498876634 535 ENERGY = 2465295065 536 POWER = 953998645
Enums for The three Destiny Weapon Types
559def into_iter( 560 iterable: collections.Iterable[Item], 561) -> Iterator[Item]: 562 """Transform an iterable into an flat iterator. 563 564 Example 565 ------- 566 ```py 567 sequence = [1,2,3] 568 for item in aiobungie.into_iter(sequence).reversed(): 569 print(item) 570 # 3 571 # 2 572 # 1 573 ``` 574 575 Parameters 576 ---------- 577 iterable: `typing.Iterable[Item]` 578 The iterable to convert. 579 580 Raises 581 ------ 582 `StopIteration` 583 If no elements are left in the iterator. 584 """ 585 return Iterator(iterable)
Transform an iterable into an flat iterator.
Example
sequence = [1,2,3]
for item in aiobungie.into_iter(sequence).reversed():
print(item)
# 3
# 2
# 1
Parameters
- iterable (
typing.Iterable[Item]): The iterable to convert.
Raises
StopIteration: If no elements are left in the iterator.
282async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError: 283 """Generates and raise exceptions on error responses.""" 284 285 # Not a JSON response, raise immediately. 286 287 # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized 288 # request with a dummy access token. I can't really do anything about this.. 289 if response.content_type != "application/json": 290 return HTTPError( 291 f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}", 292 http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE, 293 ) 294 295 body = await response.json() 296 message: str = body.get("Message", "UNDEFINED_MESSAGE") 297 error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS") 298 message_data: dict[str, str] = body.get("MessageData", {}) 299 throttle_seconds: int = body.get("ThrottleSeconds", 0) 300 error_code: int = body.get("ErrorCode", 0) 301 302 # Standard HTTP status. 303 if response.status == http.HTTPStatus.NOT_FOUND: 304 return NotFound( 305 message=message, 306 error_code=error_code, 307 throttle_seconds=throttle_seconds, 308 url=str(response.real_url), 309 body=body, 310 headers=response.headers, 311 error_status=error_status, 312 message_data=message_data, 313 ) 314 315 elif response.status == http.HTTPStatus.FORBIDDEN: 316 return Forbidden( 317 message=message, 318 error_code=error_code, 319 throttle_seconds=throttle_seconds, 320 url=str(response.real_url), 321 body=body, 322 headers=response.headers, 323 error_status=error_status, 324 message_data=message_data, 325 ) 326 327 elif response.status == http.HTTPStatus.UNAUTHORIZED: 328 return Unauthorized( 329 message=message, 330 error_code=error_code, 331 throttle_seconds=throttle_seconds, 332 url=str(response.real_url), 333 body=body, 334 headers=response.headers, 335 error_status=error_status, 336 message_data=message_data, 337 ) 338 339 elif response.status == http.HTTPStatus.BAD_REQUEST: 340 # Membership needs to be alone. 341 if error_status == "InvalidParameters": 342 return MembershipTypeError( 343 message=message, 344 body=body, 345 headers=response.headers, 346 url=str(response.url), 347 membership_type=message_data["membershipType"], 348 required_membership=message_data["membershipInfo.membershipType"], 349 membership_id=int(message_data["membershipId"]), 350 ) 351 return BadRequest( 352 message=message, 353 body=body, 354 headers=response.headers, 355 url=str(response.url), 356 ) 357 358 status = http.HTTPStatus(response.status) 359 360 if 400 <= status < 500: 361 return ResponseError( 362 message=message, 363 error_code=error_code, 364 throttle_seconds=throttle_seconds, 365 url=str(response.real_url), 366 body=body, 367 headers=response.headers, 368 error_status=error_status, 369 message_data=message_data, 370 http_status=status, 371 ) 372 373 # Need to self handle ~5xx errors 374 elif 500 <= status < 600: 375 # No API key or method requires OAuth2 most likely. 376 if error_status in { 377 "ApiKeyMissingFromRequest", 378 "WebAuthRequired", 379 "ApiInvalidOrExpiredKey", 380 "AuthenticationInvalid", 381 "AuthorizationCodeInvalid", 382 }: 383 return Unauthorized( 384 message=message, 385 error_code=error_code, 386 throttle_seconds=throttle_seconds, 387 url=str(response.real_url), 388 body=body, 389 headers=response.headers, 390 error_status=error_status, 391 message_data=message_data, 392 ) 393 394 # Anything contains not found. 395 elif ( 396 "NotFound" in error_status or error_status == "UserCannotFindRequestedUser" 397 ): 398 return NotFound( 399 message=message, 400 error_code=error_code, 401 throttle_seconds=throttle_seconds, 402 url=str(response.real_url), 403 body=body, 404 headers=response.headers, 405 error_status=error_status, 406 message_data=message_data, 407 ) 408 409 # Other 5xx errors. 410 else: 411 return InternalServerError( 412 message=message, 413 error_code=error_code, 414 throttle_seconds=throttle_seconds, 415 url=str(response.real_url), 416 body=body, 417 headers=response.headers, 418 error_status=error_status, 419 message_data=message_data, 420 http_status=status, 421 ) 422 # Something else. 423 else: 424 return HTTPException( 425 message=message, 426 error_code=error_code, 427 throttle_seconds=throttle_seconds, 428 url=str(response.real_url), 429 body=body, 430 headers=response.headers, 431 error_status=error_status, 432 message_data=message_data, 433 http_status=status, 434 )
Generates and raise exceptions on error responses.
437def stringify_http_message(headers: collections.Mapping[str, str]) -> str: 438 return ( 439 "{ \n" 440 + "\n".join( # noqa: W503 441 f"{f' {key}'}: {value}" 442 if key not in ("Authorization", "X-API-KEY") 443 else f" {key}: HIDDEN_TOKEN" 444 for key, value in headers.items() 445 ) 446 + "\n}" # noqa: W503 447 )